diff --git a/build/ExpoStoreReview.d.ts b/build/ExpoStoreReview.d.ts
index 00e8119..ed3992e 100644
--- a/build/ExpoStoreReview.d.ts
+++ b/build/ExpoStoreReview.d.ts
@@ -1,6 +1,9 @@
 declare const _default: Partial<{
     isAvailableAsync: () => Promise<boolean>;
     requestReview: () => Promise<void>;
+    prePromptReview: () => Promise<void>;
+    resetReviewState: () => Promise<void>;
+    hasUserRated: () => Promise<boolean>;
 }>;
 export default _default;
 //# sourceMappingURL=ExpoStoreReview.d.ts.map
\ No newline at end of file
diff --git a/build/ExpoStoreReview.d.ts.map b/build/ExpoStoreReview.d.ts.map
index aec682b..0a49993 100644
--- a/build/ExpoStoreReview.d.ts.map
+++ b/build/ExpoStoreReview.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"ExpoStoreReview.d.ts","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"wBACqB,OAAO,CAAC;IAC3B,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC,CAAC;AAHF,wBAGG"}
\ No newline at end of file
+{"version":3,"file":"ExpoStoreReview.d.ts","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"wBACqB,OAAO,CAAC;IAC3B,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,YAAY,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACtC,CAAC;AANF,wBAMG"}
\ No newline at end of file
diff --git a/build/ExpoStoreReview.d.ts.map.orig b/build/ExpoStoreReview.d.ts.map.orig
new file mode 100644
index 0000000..4e06d74
--- /dev/null
+++ b/build/ExpoStoreReview.d.ts.map.orig
@@ -0,0 +1 @@
+{"version":3,"file":"ExpoStoreReview.d.ts","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"wBACqB,OAAO,CAAC;IAC3B,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,CAAC;AALF,wBAKG"}
\ No newline at end of file
diff --git a/build/ExpoStoreReview.d.ts.map.rej b/build/ExpoStoreReview.d.ts.map.rej
new file mode 100644
index 0000000..93ac91c
--- /dev/null
+++ b/build/ExpoStoreReview.d.ts.map.rej
@@ -0,0 +1,5 @@
+@@ -1,1 +1,1 @@
+-{"version":3,"file":"ExpoStoreReview.d.ts","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"wBACqB,OAAO,CAAC;IAC3B,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC,CAAC;AAHF,wBAGG"}
+\ No newline at end of line
++{"version":3,"file":"ExpoStoreReview.d.ts","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"wBACqB,OAAO,CAAC;IAC3B,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,YAAY,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACtC,CAAC;AANF,wBAMG"}
+\ No newline at end of line
diff --git a/build/ExpoStoreReview.js.map b/build/ExpoStoreReview.js.map
index 80fdadb..7fdbdfa 100644
--- a/build/ExpoStoreReview.js.map
+++ b/build/ExpoStoreReview.js.map
@@ -1 +1 @@
-{"version":3,"file":"ExpoStoreReview.js","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,eAAe,EAGb,CAAC","sourcesContent":["// Unimplemented on web\nexport default {} as Partial<{\n  isAvailableAsync: () => Promise<boolean>;\n  requestReview: () => Promise<void>;\n}>;\n"]}
\ No newline at end of file
+{"version":3,"file":"ExpoStoreReview.js","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,eAAe,EAMb,CAAC","sourcesContent":["// Unimplemented on web\nexport default {} as Partial<{\n  isAvailableAsync: () => Promise<boolean>;\n  requestReview: () => Promise<void>;\n  prePromptReview: () => Promise<void>;\n  resetReviewState: () => Promise<void>;\n  hasUserRated: () => Promise<boolean>;\n}>;\n"]}
\ No newline at end of file
diff --git a/build/ExpoStoreReview.js.map.orig b/build/ExpoStoreReview.js.map.orig
new file mode 100644
index 0000000..867130c
--- /dev/null
+++ b/build/ExpoStoreReview.js.map.orig
@@ -0,0 +1 @@
+{"version":3,"file":"ExpoStoreReview.js","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,eAAe,EAKb,CAAC","sourcesContent":["// Unimplemented on web\nexport default {} as Partial<{\n  isAvailableAsync: () => Promise<boolean>;\n  requestReview: () => Promise<void>;\n  prePromptReview: () => Promise<void>;\n  resetReviewState: () => Promise<void>;\n}>;\n"]}
\ No newline at end of file
diff --git a/build/ExpoStoreReview.js.map.rej b/build/ExpoStoreReview.js.map.rej
new file mode 100644
index 0000000..8a0b07d
--- /dev/null
+++ b/build/ExpoStoreReview.js.map.rej
@@ -0,0 +1,5 @@
+@@ -1,1 +1,1 @@
+-{"version":3,"file":"ExpoStoreReview.js","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,eAAe,EAGb,CAAC","sourcesContent":["// Unimplemented on web\nexport default {} as Partial<{\n  isAvailableAsync: () => Promise<boolean>;\n  requestReview: () => Promise<void>;\n}>;\n"]}
+\ No newline at end of line
++{"version":3,"file":"ExpoStoreReview.js","sourceRoot":"","sources":["../src/ExpoStoreReview.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,eAAe,EAMb,CAAC","sourcesContent":["// Unimplemented on web\nexport default {} as Partial<{\n  isAvailableAsync: () => Promise<boolean>;\n  requestReview: () => Promise<void>;\n  prePromptReview: () => Promise<void>;\n  resetReviewState: () => Promise<void>;\n  hasUserRated: () => Promise<boolean>;\n}>;\n"]}
+\ No newline at end of line
diff --git a/build/ExpoStoreReview.native.js b/build/ExpoStoreReview.native.js
index 39755d3..a110bfe 100644
--- a/build/ExpoStoreReview.native.js
+++ b/build/ExpoStoreReview.native.js
@@ -1,3 +1,4 @@
 import { requireNativeModule } from 'expo-modules-core';
-export default requireNativeModule('ExpoStoreReview');
+
+export default globalThis && globalThis.expo && globalThis.expo.modules && globalThis.expo.modules.ExpoStoreReview ? requireNativeModule('ExpoStoreReview') : {};
 //# sourceMappingURL=ExpoStoreReview.native.js.map
diff --git a/build/StoreReview.d.ts b/build/StoreReview.d.ts
index 00cf30a..0f91d73 100644
--- a/build/StoreReview.d.ts
+++ b/build/StoreReview.d.ts
@@ -7,6 +7,25 @@
  * - On Web, it will resolve to `false`.
  */
 export declare function isAvailableAsync(): Promise<boolean>;
+/**
+ * Shows a pre-prompt alert asking the user if they'd like to rate the app. If they select "Yes",
+ * it will then show the native store review prompt. This is useful for improving review conversion rates.
+ * Currently only available on iOS.
+ */
+export declare function prePromptReview(): Promise<void>;
+/**
+ * Resets the review state stored in UserDefaults. This allows you to clear the
+ * tracking of whether the user has already been prompted for a review.
+ * Currently only available on iOS.
+ */
+export declare function resetReviewState(): Promise<void>;
+/**
+ * Checks whether the user has already rated the app (i.e., they selected "Rate Now"
+ * in the pre-prompt dialog). This can be used to conditionally show or hide rating prompts.
+ * Currently only available on iOS.
+ * @return A promise that resolves to true if the user has rated, false otherwise.
+ */
+export declare function hasUserRated(): Promise<boolean>;
 /**
  * In ideal circumstances this will open a native modal and allow the user to select a star rating
  * that will then be applied to the App Store, without leaving the app. If the device is running
diff --git a/build/StoreReview.d.ts.map b/build/StoreReview.d.ts.map
index 4ce88d2..6f7f508 100644
--- a/build/StoreReview.d.ts.map
+++ b/build/StoreReview.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"StoreReview.d.ts","sourceRoot":"","sources":["../src/StoreReview.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAEzD;AAGD;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAmBnD;AAGD;;;;;GAKG;AACH,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAQxC;AAGD;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAElD"}
\ No newline at end of file
+{"version":3,"file":"StoreReview.d.ts","sourceRoot":"","sources":["../src/StoreReview.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAEzD;AAGD;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAMrD;AAGD;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMtD;AAGD;;;;;GAKG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAOrD;AAGD;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAmBnD;AAGD;;;;;GAKG;AACH,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAQxC;AAGD;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAElD"}
\ No newline at end of file
diff --git a/build/StoreReview.js b/build/StoreReview.js
index 5ddf98b..232423f 100644
--- a/build/StoreReview.js
+++ b/build/StoreReview.js
@@ -15,6 +15,47 @@ export async function isAvailableAsync() {
     return StoreReview.isAvailableAsync?.() ?? false;
 }
 // @needsAudit
+/**
+ * Shows a pre-prompt alert asking the user if they'd like to rate the app. If they select "Yes",
+ * it will then show the native store review prompt. This is useful for improving review conversion rates.
+ * Currently only available on iOS.
+ */
+export async function prePromptReview() {
+    if (StoreReview?.prePromptReview) {
+        return StoreReview.prePromptReview();
+    }
+    // Fallback: if prePromptReview is not available, just do nothing
+    // (This will be the case on web and Android)
+}
+// @needsAudit
+/**
+ * Resets the review state by clearing the last review request timestamp and rating status.
+ * This is useful for testing or if you want to allow the review prompt to be shown again
+ * regardless of the normal rate limiting. Currently only available on iOS.
+ */
+export async function resetReviewState() {
+    if (StoreReview?.resetReviewState) {
+        return StoreReview.resetReviewState();
+    }
+    // Fallback: if resetReviewState is not available, just do nothing
+    // (This will be the case on web and Android)
+}
+// @needsAudit
+/**
+ * Checks whether the user has already rated the app (i.e., they selected "Rate Now"
+ * in the pre-prompt dialog). This can be used to conditionally show or hide rating prompts.
+ * Currently only available on iOS.
+ * @return A promise that resolves to true if the user has rated, false otherwise.
+ */
+export async function hasUserRated() {
+    if (StoreReview?.hasUserRated) {
+        return StoreReview.hasUserRated();
+    }
+    // Fallback: if hasUserRated is not available, return false
+    // (This will be the case on web and Android)
+    return false;
+}
+// @needsAudit
 /**
  * In ideal circumstances this will open a native modal and allow the user to select a star rating
  * that will then be applied to the App Store, without leaving the app. If the device is running
diff --git a/build/StoreReview.js.map b/build/StoreReview.js.map
index cd16b26..56882e2 100644
--- a/build/StoreReview.js.map
+++ b/build/StoreReview.js.map
@@ -1 +1 @@
-{"version":3,"file":"StoreReview.js","sourceRoot":"","sources":["../src/StoreReview.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAE5C,cAAc;AACd;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,WAAW,CAAC,gBAAgB,EAAE,EAAE,IAAI,KAAK,CAAC;AACnD,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,WAAW,EAAE,aAAa,EAAE,CAAC;QAC/B,OAAO,WAAW,CAAC,aAAa,EAAE,CAAC;IACrC,CAAC;IACD,6GAA6G;IAC7G,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;IACvB,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAC3E,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;SAAM,CAAC;QACN,iDAAiD;QACjD,OAAO,CAAC,IAAI,CACV,+JAA+J,CAChK,CAAC;IACJ,CAAC;AACH,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;IACxC,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,UAAU,EAAE,GAAG,EAAE,CAAC;QAC7C,OAAO,UAAU,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC;IAC5C,CAAC;SAAM,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,UAAU,EAAE,OAAO,EAAE,CAAC;QAC5D,OAAO,UAAU,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC;IACjD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,OAAO,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,gBAAgB,EAAE,CAAC,CAAC;AACpD,CAAC","sourcesContent":["import Constants from 'expo-constants';\nimport { Platform } from 'expo-modules-core';\nimport { Linking } from 'react-native';\n\nimport StoreReview from './ExpoStoreReview';\n\n// @needsAudit\n/**\n * Determines if the platform has the capabilities to use `StoreReview.requestReview()`.\n * @return\n * This returns a promise fulfills with `boolean`, depending on the platform:\n * - On iOS, it will resolve to `true` unless the app is distributed through TestFlight.\n * - On Android, it will resolve to `true` if the device is running Android 5.0+.\n * - On Web, it will resolve to `false`.\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n  return StoreReview.isAvailableAsync?.() ?? false;\n}\n\n// @needsAudit\n/**\n * In ideal circumstances this will open a native modal and allow the user to select a star rating\n * that will then be applied to the App Store, without leaving the app. If the device is running\n * a version of Android lower than 5.0, this will attempt to get the store URL and link the user to it.\n */\nexport async function requestReview(): Promise<void> {\n  if (StoreReview?.requestReview) {\n    return StoreReview.requestReview();\n  }\n  // If StoreReview is unavailable then get the store URL from `app.config.js` or `app.json` and open the store\n  const url = storeUrl();\n  if (url) {\n    const supported = await Linking.canOpenURL(url);\n    if (!supported) {\n      console.warn(\"StoreReview.requestReview(): Can't open store url: \", url);\n    } else {\n      await Linking.openURL(url);\n    }\n  } else {\n    // If the store URL is missing, let the dev know.\n    console.warn(\n      \"StoreReview.requestReview(): Couldn't link to store, please make sure the `android.playStoreUrl` & `ios.appStoreUrl` fields are filled out in your `app.json`\"\n    );\n  }\n}\n\n// @needsAudit\n/**\n * This uses the `Constants` API to get the `Constants.expoConfig.ios.appStoreUrl` on iOS, or the\n * `Constants.expoConfig.android.playStoreUrl` on Android.\n *\n * On Web this will return `null`.\n */\nexport function storeUrl(): string | null {\n  const expoConfig = Constants.expoConfig;\n  if (Platform.OS === 'ios' && expoConfig?.ios) {\n    return expoConfig.ios.appStoreUrl ?? null;\n  } else if (Platform.OS === 'android' && expoConfig?.android) {\n    return expoConfig.android.playStoreUrl ?? null;\n  }\n  return null;\n}\n\n// @needsAudit\n/**\n * @return This returns a promise that fulfills to `true` if `StoreReview.requestReview()` is capable\n * directing the user to some kind of store review flow. If the app config (`app.json`) does not\n * contain store URLs and native store review capabilities are not available then the promise\n * will fulfill to `false`.\n *\n * @example\n * ```ts\n * if (await StoreReview.hasAction()) {\n *   // you can call StoreReview.requestReview()\n * }\n * ```\n */\nexport async function hasAction(): Promise<boolean> {\n  return !!storeUrl() || (await isAvailableAsync());\n}\n"]}
\ No newline at end of file
+{"version":3,"file":"StoreReview.js","sourceRoot":"","sources":["../src/StoreReview.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAE5C,cAAc;AACd;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,WAAW,CAAC,gBAAgB,EAAE,EAAE,IAAI,KAAK,CAAC;AACnD,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,WAAW,EAAE,eAAe,EAAE,CAAC;QACjC,OAAO,WAAW,CAAC,eAAe,EAAE,CAAC;IACvC,CAAC;IACD,iEAAiE;IACjE,6CAA6C;AAC/C,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,WAAW,EAAE,gBAAgB,EAAE,CAAC;QAClC,OAAO,WAAW,CAAC,gBAAgB,EAAE,CAAC;IACxC,CAAC;IACD,iEAAiE;IACjE,6CAA6C;AAC/C,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,WAAW,EAAE,YAAY,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,YAAY,EAAE,CAAC;IACpC,CAAC;IACD,yEAAyE;IACzE,6CAA6C;IAC7C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,WAAW,EAAE,aAAa,EAAE,CAAC;QAC/B,OAAO,WAAW,CAAC,aAAa,EAAE,CAAC;IACrC,CAAC;IACD,6GAA6G;IAC7G,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;IACvB,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAC3E,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;SAAM,CAAC;QACN,iDAAiD;QACjD,OAAO,CAAC,IAAI,CACV,+JAA+J,CAChK,CAAC;IACJ,CAAC;AACH,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;IACxC,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,UAAU,EAAE,GAAG,EAAE,CAAC;QAC7C,OAAO,UAAU,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC;IAC5C,CAAC;SAAM,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,UAAU,EAAE,OAAO,EAAE,CAAC;QAC5D,OAAO,UAAU,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC;IACjD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,OAAO,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,gBAAgB,EAAE,CAAC,CAAC;AACpD,CAAC","sourcesContent":["import Constants from 'expo-constants';\nimport { Platform } from 'expo-modules-core';\nimport { Linking } from 'react-native';\n\nimport StoreReview from './ExpoStoreReview';\n\n// @needsAudit\n/**\n * Determines if the platform has the capabilities to use `StoreReview.requestReview()`.\n * @return\n * This returns a promise fulfills with `boolean`, depending on the platform:\n * - On iOS, it will resolve to `true` unless the app is distributed through TestFlight.\n * - On Android, it will resolve to `true` if the device is running Android 5.0+.\n * - On Web, it will resolve to `false`.\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n  return StoreReview.isAvailableAsync?.() ?? false;\n}\n\n// @needsAudit\n/**\n * Shows a pre-prompt alert asking the user if they'd like to rate the app. If they select \"Yes\",\n * it will then show the native store review prompt. This is useful for improving review conversion rates.\n * Currently only available on iOS.\n */\nexport async function prePromptReview(): Promise<void> {\n  if (StoreReview?.prePromptReview) {\n    return StoreReview.prePromptReview();\n  }\n  // Fallback: if prePromptReview is not available, just do nothing\n  // (This will be the case on web and Android)\n}\n\n// @needsAudit\n/**\n * Resets the review state stored in UserDefaults. This allows you to clear the\n * tracking of whether the user has already been prompted for a review.\n * Currently only available on iOS.\n */\nexport async function resetReviewState(): Promise<void> {\n  if (StoreReview?.resetReviewState) {\n    return StoreReview.resetReviewState();\n  }\n  // Fallback: if resetReviewState is not available, just do nothing\n  // (This will be the case on web and Android)\n}\n\n// @needsAudit\n/**\n * Checks whether the user has already rated the app (i.e., they selected \"Rate Now\"\n * in the pre-prompt dialog). This can be used to conditionally show or hide rating prompts.\n * Currently only available on iOS.\n * @return A promise that resolves to true if the user has rated, false otherwise.\n */\nexport async function hasUserRated(): Promise<boolean> {\n  if (StoreReview?.hasUserRated) {\n    return StoreReview.hasUserRated();\n  }\n  // Fallback: if hasUserRated is not available, return false\n  // (This will be the case on web and Android)\n  return false;\n}\n\n// @needsAudit\n/**\n * In ideal circumstances this will open a native modal and allow the user to select a star rating\n * that will then be applied to the App Store, without leaving the app. If the device is running\n * a version of Android lower than 5.0, this will attempt to get the store URL and link the user to it.\n */\nexport async function requestReview(): Promise<void> {\n  if (StoreReview?.requestReview) {\n    return StoreReview.requestReview();\n  }\n  // If StoreReview is unavailable then get the store URL from `app.config.js` or `app.json` and open the store\n  const url = storeUrl();\n  if (url) {\n    const supported = await Linking.canOpenURL(url);\n    if (!supported) {\n      console.warn(\"StoreReview.requestReview(): Can't open store url: \", url);\n    } else {\n      await Linking.openURL(url);\n    }\n  } else {\n    // If the store URL is missing, let the dev know.\n    console.warn(\n      \"StoreReview.requestReview(): Couldn't link to store, please make sure the `android.playStoreUrl` & `ios.appStoreUrl` fields are filled out in your `app.json`\"\n    );\n  }\n}\n\n// @needsAudit\n/**\n * This uses the `Constants` API to get the `Constants.expoConfig.ios.appStoreUrl` on iOS, or the\n * `Constants.expoConfig.android.playStoreUrl` on Android.\n *\n * On Web this will return `null`.\n */\nexport function storeUrl(): string | null {\n  const expoConfig = Constants.expoConfig;\n  if (Platform.OS === 'ios' && expoConfig?.ios) {\n    return expoConfig.ios.appStoreUrl ?? null;\n  } else if (Platform.OS === 'android' && expoConfig?.android) {\n    return expoConfig.android.playStoreUrl ?? null;\n  }\n  return null;\n}\n\n// @needsAudit\n/**\n * @return This returns a promise that fulfills to `true` if `StoreReview.requestReview()` is capable\n * directing the user to some kind of store review flow. If the app config (`app.json`) does not\n * contain store URLs and native store review capabilities are not available then the promise\n * will fulfill to `false`.\n *\n * @example\n * ```ts\n * if (await StoreReview.hasAction()) {\n *   // you can call StoreReview.requestReview()\n * }\n * ```\n */\nexport async function hasAction(): Promise<boolean> {\n  return !!storeUrl() || (await isAvailableAsync());\n}\n"]}
\ No newline at end of file
diff --git a/ios/StoreReviewModule.swift b/ios/StoreReviewModule.swift
index c44c468..4eb6ea0 100644
--- a/ios/StoreReviewModule.swift
+++ b/ios/StoreReviewModule.swift
@@ -1,5 +1,8 @@
 import ExpoModulesCore
 import StoreKit
+import UIKit
+
+private let HAS_RATED_KEY = "anything_has_rated"
 
 public class StoreReviewModule: Module {
   public func definition() -> ModuleDefinition {
@@ -9,11 +12,55 @@ public class StoreReviewModule: Module {
       return !isRunningFromTestFlight()
     }
 
+    AsyncFunction("prePromptReview") {
+      if isRunningFromTestFlight() {
+        return
+      }
+
+      try await MainActor.run {
+        let defaults = UserDefaults.standard
+
+        if defaults.bool(forKey: HAS_RATED_KEY) {
+          return
+        }
+
+        guard let currentScene = getForegroundActiveScene() else {
+          throw MissingCurrentWindowSceneException()
+        }
+
+        let keyWindow = currentScene.windows.first(where: { $0.isKeyWindow })
+        guard let rootVC = keyWindow?.rootViewController else {
+          throw MissingCurrentWindowSceneException()
+        }
+
+        let alert = UIAlertController(
+          title: "Thanks for using Anything!",
+          message: "Share what you love about Anything in the App Store. Your review will help us reach more people.",
+          preferredStyle: .alert
+        )
+
+        let noAction = UIAlertAction(title: "No Thanks", style: .cancel, handler: nil)
+
+        let yesAction = UIAlertAction(title: "Rate Now", style: .default) { _ in
+          defaults.set(true, forKey: HAS_RATED_KEY)
+
+          if #available(iOS 16.0, *) {
+            AppStore.requestReview(in: currentScene)
+          } else {
+            SKStoreReviewController.requestReview(in: currentScene)
+          }
+        }
+
+        alert.addAction(noAction)
+        alert.addAction(yesAction)
+
+        rootVC.present(alert, animated: true, completion: nil)
+      }
+    }
+
     AsyncFunction("requestReview") {
       try await MainActor.run {
         guard let currentScene = getForegroundActiveScene() else {
-          // If no valid foreground scene is found, throw an exception
-          // as the review prompt won't be visible in background
           throw MissingCurrentWindowSceneException()
         }
         if #available(iOS 16.0, *) {
@@ -23,23 +70,30 @@ public class StoreReviewModule: Module {
         }
       }
     }
+
+    AsyncFunction("resetReviewState") {
+      let defaults = UserDefaults.standard
+      defaults.removeObject(forKey: HAS_RATED_KEY)
+    }
+
+    AsyncFunction("hasUserRated") { () -> Bool in
+      let defaults = UserDefaults.standard
+      return defaults.bool(forKey: HAS_RATED_KEY)
+    }
+    
   }
 
   private func getForegroundActiveScene() -> UIWindowScene? {
-    // First try to find a foreground active scene
-    if let activeScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
+    if let activeScene = UIApplication.shared.connectedScenes
+      .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
       return activeScene
     }
 
-    // If no foreground active scene is found (e.g., app is in App Switcher),
-    // try to find any foreground inactive scene
-    if let foregroundScene = UIApplication.shared.connectedScenes.first(where: {
-      $0.activationState == .foregroundInactive
-    }) as? UIWindowScene {
+    if let foregroundScene = UIApplication.shared.connectedScenes
+      .first(where: { $0.activationState == .foregroundInactive }) as? UIWindowScene {
       return foregroundScene
     }
 
-    // If no valid foreground scene is found, return nil
     return nil
   }
 
@@ -48,12 +102,7 @@ public class StoreReviewModule: Module {
     return false
     #endif
 
-    // For apps distributed through TestFlight or intalled from Xcode the receipt file is named "StoreKit/sandboxReceipt"
-    // instead of "StoreKit/receipt"
     let isSandboxEnv = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
-
-    // Apps distributed through TestFlight or the App Store will not have an embedded provisioning profile
-    // Source: https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles#Profile-location
     return isSandboxEnv && !hasEmbeddedMobileProvision()
   }
 
diff --git a/src/ExpoStoreReview.ts b/src/ExpoStoreReview.ts
index cb9ee95..94b9581 100644
--- a/src/ExpoStoreReview.ts
+++ b/src/ExpoStoreReview.ts
@@ -2,4 +2,7 @@
 export default {} as Partial<{
   isAvailableAsync: () => Promise<boolean>;
   requestReview: () => Promise<void>;
+  prePromptReview: () => Promise<void>;
+  resetReviewState: () => Promise<void>;
+  hasUserRated: () => Promise<boolean>;
 }>;
diff --git a/src/StoreReview.ts b/src/StoreReview.ts
index a9b9094..570caa6 100644
--- a/src/StoreReview.ts
+++ b/src/StoreReview.ts
@@ -17,6 +17,20 @@ export async function isAvailableAsync(): Promise<boolean> {
   return StoreReview.isAvailableAsync?.() ?? false;
 }
 
+// @needsAudit
+/**
+ * Shows a pre-prompt alert asking the user if they'd like to rate the app. If they select "Yes",
+ * it will then show the native store review prompt. This is useful for improving review conversion rates.
+ * Currently only available on iOS.
+ */
+export async function prePromptReview(): Promise<void> {
+  if (StoreReview?.prePromptReview) {
+    return StoreReview.prePromptReview();
+  }
+  // Fallback: if prePromptReview is not available, just do nothing
+  // (This will be the case on web and Android)
+}
+
 // @needsAudit
 /**
  * In ideal circumstances this will open a native modal and allow the user to select a star rating
@@ -78,3 +92,33 @@ export function storeUrl(): string | null {
 export async function hasAction(): Promise<boolean> {
   return !!storeUrl() || (await isAvailableAsync());
 }
+
+// @needsAudit
+/**
+ * Resets the review state stored in UserDefaults. This allows you to clear the
+ * tracking of whether the user has already been prompted for a review.
+ * Currently only available on iOS.
+ */
+export async function resetReviewState(): Promise<void> {
+  if (StoreReview?.resetReviewState) {
+    return StoreReview.resetReviewState();
+  }
+  // Fallback: if resetReviewState is not available, just do nothing
+  // (This will be the case on web and Android)
+}
+
+// @needsAudit
+/**
+ * Checks whether the user has already rated the app (i.e., they selected "Rate Now"
+ * in the pre-prompt dialog). This can be used to conditionally show or hide rating prompts.
+ * Currently only available on iOS.
+ * @return A promise that resolves to true if the user has rated, false otherwise.
+ */
+export async function hasUserRated(): Promise<boolean> {
+  if (StoreReview?.hasUserRated) {
+    return StoreReview.hasUserRated();
+  }
+  // Fallback: if hasUserRated is not available, return false
+  // (This will be the case on web and Android)
+  return false;
+}
