diff --git a/content/docs/images/gc_unity.jpg b/content/docs/images/gc_unity.jpg
new file mode 100644
index 0000000..3530426
Binary files /dev/null and b/content/docs/images/gc_unity.jpg differ
diff --git a/content/docs/images/unity-game-controller-support-placeholder.svg b/content/docs/images/unity-game-controller-support-placeholder.svg
new file mode 100644
index 0000000..7b53287
--- /dev/null
+++ b/content/docs/images/unity-game-controller-support-placeholder.svg
@@ -0,0 +1,9 @@
+
diff --git a/content/docs/images/unity-package-manager-git-url-placeholder.svg b/content/docs/images/unity-package-manager-git-url-placeholder.svg
new file mode 100644
index 0000000..6bc8a19
--- /dev/null
+++ b/content/docs/images/unity-package-manager-git-url-placeholder.svg
@@ -0,0 +1,9 @@
+
diff --git a/content/docs/images/upm_add.jpg b/content/docs/images/upm_add.jpg
new file mode 100644
index 0000000..eb970de
Binary files /dev/null and b/content/docs/images/upm_add.jpg differ
diff --git a/content/docs/meta.json b/content/docs/meta.json
index 0136e01..463681e 100644
--- a/content/docs/meta.json
+++ b/content/docs/meta.json
@@ -16,7 +16,8 @@
"android",
"expo",
"flutter",
+ "unity",
"react-native",
"community"
]
-}
\ No newline at end of file
+}
diff --git a/content/docs/unity/changelog.mdx b/content/docs/unity/changelog.mdx
new file mode 100644
index 0000000..4d77297
--- /dev/null
+++ b/content/docs/unity/changelog.mdx
@@ -0,0 +1,86 @@
+---
+title: "Changelog"
+description: "Changelog for the Superwall Unity SDK beta."
+---
+
+# Changelog
+
+All notable changes to this package will be documented in this file.
+
+## [0.2.3]
+
+### Breaking Changes
+
+- `Configure` completion signature changed from `Action` to `Action` to match the native SDKs' `Result` semantics. The result exposes `IsSuccess` and a typed `FailedResult.Error` on failure. Android now propagates SDK init errors through this; iOS still always signals success since SuperwallKit's completion has no failure variant.
+
+### Cleanup
+
+- Renamed asmdef files to `Superwall.*`
+
+## [0.2.1]
+
+## Enhancements
+
+### New APIs
+
+- `SetLocalResources(Dictionary)` - map asset names to local file paths for paywall WebViews (Android only)
+
+### Delegate Fixes
+
+- Android: added `willRedeemLink`, `didRedeemLink`, `userAttributesDidChange` delegate callbacks
+- iOS: added `handleSuperwallDeepLink`, `userAttributesDidChange` delegate callbacks
+- iOS: added `ShowAlert` no-op stub to prevent missing symbol crash
+
+## [0.2.0]
+
+### Android Support
+
+- Full Android support via bundled `.androidlib` Gradle module - no manual `mainTemplate.gradle` setup needed
+- Kotlin bridge compiled with Kotlin 2.0.21 to match Superwall Android SDK 2.x
+- Custom `ActivityProvider` for Unity ensures paywall presentation works correctly
+- AndroidManifest with required activity declarations merged automatically
+
+### New APIs
+
+- `Purchase(productId, callback)` - programmatic purchase without a paywall
+- `GetProducts(productIds, callback)` - fetch product details by ID
+- `GetAssignments(callback)` - get experiment assignments without confirming
+- `ShowAlert(title, message, ...)` - show alerts on the current paywall
+- `RefreshConfiguration()` - force SDK config refresh
+
+### Options
+
+- Full `SuperwallOptions` parsing on both platforms (was incomplete)
+- Added `PaywallOptions.UseCachedTemplates` and `PaywallOptions.TimeoutAfter`
+- `TestModeBehavior`, `NetworkEnvironment`, `Paywalls.*`, `Logging.Scopes` now properly passed to native SDKs
+
+### Delegate & Callbacks
+
+- All `ISuperwallDelegate` callbacks now receive deserialized objects instead of null
+- `SubscriptionStatus` getter properly deserializes native state (was always returning Unknown)
+- All async getters (`Entitlements`, `CustomerInfo`, `PaywallInfo`, `PresentationResult`, `ConfirmedAssignment`, `RestorationResult`) now deserialize correctly
+- Fixed async callback mechanism - was dropping response data, causing `Configure` completion to always return false
+
+### iOS
+
+- Purchase controller flow implemented with async continuations
+- Integration attributes mapping implemented
+- Full options parity with Android
+
+### Cleanup
+
+- Removed legacy `com.ian_unity558.com.superwall.sdk` package
+- Removed stale `EnsureAndroidGradleDependency` editor script (replaced by `.androidlib`)
+
+## [0.1.1]
+
+- Android package support
+- Handler callback arguments
+- More properties implemented
+- Improved option support
+
+## [0.1.0]
+
+### This is the first release of _<com.superwall.sdk>_.
+
+- iOS support, registering and callbacks
diff --git a/content/docs/unity/guides/advanced-configuration.mdx b/content/docs/unity/guides/advanced-configuration.mdx
new file mode 100644
index 0000000..0822cd6
--- /dev/null
+++ b/content/docs/unity/guides/advanced-configuration.mdx
@@ -0,0 +1,221 @@
+---
+title: "Advanced Configuration"
+description: "Configure beta Superwall Unity SDK options and advanced APIs."
+---
+
+`SuperwallOptions` lets you tune paywall behavior, logging, locale, test mode, and platform-specific
+behavior at configuration time.
+
+```csharp C#
+using System.Collections.Generic;
+using Superwall;
+
+var options = new SuperwallOptions
+{
+ NetworkEnvironment = NetworkEnvironment.Release,
+ TestModeBehavior = TestModeBehavior.Automatic,
+ IsGameControllerEnabled = true,
+ Logging = new Logging
+ {
+ Level = LogLevel.Debug,
+ Scopes = new List { LogScope.PaywallPresentation }
+ },
+ Paywalls = new PaywallOptions
+ {
+ ShouldPreload = true,
+ AutomaticallyDismiss = true,
+ ShouldShowPurchaseFailureAlert = true,
+ RestoreFailed = new RestoreFailed
+ {
+ Title = "No Subscription Found",
+ Message = "We couldn't find an active subscription for your account.",
+ CloseButtonTitle = "Okay"
+ }
+ }
+};
+
+Superwall.Configure("MY_PUBLIC_API_KEY", options: options);
+```
+
+## `SuperwallOptions`
+
+
+
+## `PaywallOptions`
+
+",
+ description: "Maps product names in paywalls to specific store product identifiers.",
+ default: "null",
+ },
+ ShouldShowWebPurchaseConfirmationAlert: {
+ type: "bool",
+ description: "Shows the web purchase confirmation alert.",
+ default: "false",
+ },
+ UseCachedTemplates: {
+ type: "bool",
+ description: "Uses cached paywall templates when available.",
+ default: "false",
+ },
+ TimeoutAfter: {
+ type: "float?",
+ description: "Optional paywall request timeout in seconds.",
+ default: "null",
+ },
+ }}
+/>
+
+## Preloading
+
+```csharp C#
+Superwall.Shared.PreloadAllPaywalls();
+
+Superwall.Shared.PreloadPaywallsForPlacements(new List
+{
+ "onboarding",
+ "upgrade"
+});
+```
+
+## Locale
+
+```csharp C#
+Superwall.Shared.LocaleIdentifier = "es_ES";
+```
+
+## Local Resources
+
+Android builds can map paywall asset names to local file paths.
+
+```csharp C#
+Superwall.Shared.SetLocalResources(new Dictionary
+{
+ { "hero_image", "/absolute/path/to/hero.png" }
+});
+```
+
+`SetLocalResources` is Android-only in the current beta. It is a no-op on iOS.
+
+## Programmatic Purchase and Products
+
+```csharp C#
+Superwall.Shared.GetProducts(new List { "monthly", "annual" }, products =>
+{
+ foreach (var product in products)
+ {
+ Debug.Log($"{product.Key}: {product.Value.LocalizedPrice}");
+ }
+});
+
+Superwall.Shared.Purchase("monthly", result =>
+{
+ Debug.Log($"Purchase result: {result.Type}");
+});
+```
+
+For normal paywall flows, prefer `RegisterPlacement`.
diff --git a/content/docs/unity/guides/custom-purchase-controller.mdx b/content/docs/unity/guides/custom-purchase-controller.mdx
new file mode 100644
index 0000000..c544498
--- /dev/null
+++ b/content/docs/unity/guides/custom-purchase-controller.mdx
@@ -0,0 +1,72 @@
+---
+title: "Custom Purchase Controller"
+description: "Use a custom purchase controller with the Unity SDK beta."
+---
+
+By default, Superwall handles purchase and restore flows through the native iOS and Android SDKs.
+Most Unity integrations should start there.
+
+Use `IPurchaseController` only when another system, such as your own store abstraction or a third
+party purchase SDK, must complete purchases and restores.
+
+## Implement `IPurchaseController`
+
+```csharp C#
+using System;
+using Superwall;
+
+public sealed class GamePurchaseController : IPurchaseController
+{
+ public void PurchaseFromAppStore(string productId, Action completion)
+ {
+ // Complete the App Store purchase with your purchase system.
+ // Then call completion with the result.
+ completion(PurchaseResult.Purchased());
+ }
+
+ public void PurchaseFromGooglePlay(
+ string productId,
+ string basePlanId,
+ string offerId,
+ Action completion
+ )
+ {
+ // Complete the Google Play purchase with your purchase system.
+ // Use basePlanId and offerId if your catalog needs them.
+ // Then call completion with the result.
+ completion(PurchaseResult.Purchased());
+ }
+
+ public void RestorePurchases(Action completion)
+ {
+ // Restore purchases with your purchase system.
+ completion(RestorationResult.Restored());
+ }
+}
+```
+
+Pass the controller when configuring Superwall:
+
+```csharp C#
+Superwall.Configure(
+ "MY_PUBLIC_API_KEY",
+ purchaseController: new GamePurchaseController()
+);
+```
+
+## Keep Subscription Status in Sync
+
+When your purchase system is the source of truth, update Superwall whenever access changes.
+
+```csharp C#
+Superwall.Shared.SubscriptionStatus = SubscriptionStatus.CreateActive(entitlements);
+```
+
+Or clear access:
+
+```csharp C#
+Superwall.Shared.SubscriptionStatus = SubscriptionStatus.CreateInactive();
+```
+
+See [Tracking Subscription State](/unity/quickstart/tracking-subscription-state) for a complete
+example.
diff --git a/content/docs/unity/guides/game-controller-input.mdx b/content/docs/unity/guides/game-controller-input.mdx
new file mode 100644
index 0000000..2c60a93
--- /dev/null
+++ b/content/docs/unity/guides/game-controller-input.mdx
@@ -0,0 +1,59 @@
+---
+title: "Game Controller Input"
+description: "Enable game controller support for Unity paywalls."
+---
+
+Unity games often need paywalls that work with touch and controller input. Superwall supports
+controller-triggered paywall actions when both the SDK and paywall template are configured for it.
+
+## Enable Controller Support in the SDK
+
+Set `IsGameControllerEnabled` when configuring Superwall.
+
+```csharp C#
+using System.Collections.Generic;
+using Superwall;
+
+var options = new SuperwallOptions
+{
+ IsGameControllerEnabled = true,
+ Logging = new Logging
+ {
+ Level = LogLevel.Debug,
+ Scopes = new List { LogScope.GameControllerManager }
+ }
+};
+
+Superwall.Configure("MY_PUBLIC_API_KEY", options: options);
+```
+
+## Enable Controller Support on the Paywall
+
+In the paywall editor, open the paywall settings and set **Game Controller Support** to **ENABLED**.
+
+
+
+After this setting is enabled, click behavior controls can map an action to one of these controller
+buttons:
+
+- `a`
+- `b`
+- `x`
+- `y`
+- `l1`
+- `l2`
+- `r1`
+- `r2`
+- `menu`
+- `options`
+
+## Test on Device
+
+Controller support depends on the native iOS or Android runtime. The Unity Editor only logs SDK
+method calls, so test with a controller connected to a real device, simulator, or emulator that
+supports controller input.
+
+
+ If touch input works but controller input does not, verify both settings:
+ `IsGameControllerEnabled` in Unity and **Game Controller Support** in the paywall editor.
+
diff --git a/content/docs/unity/guides/using-superwall-delegate.mdx b/content/docs/unity/guides/using-superwall-delegate.mdx
new file mode 100644
index 0000000..c4a25f4
--- /dev/null
+++ b/content/docs/unity/guides/using-superwall-delegate.mdx
@@ -0,0 +1,104 @@
+---
+title: "Using the Superwall Delegate"
+description: "Receive Superwall lifecycle callbacks in Unity."
+---
+
+Implement `ISuperwallDelegate` when your game needs callbacks for paywall lifecycle events,
+subscription changes, custom paywall actions, deep links, or SDK logs.
+
+## Set a Delegate
+
+Attach a delegate `MonoBehaviour` after `Superwall.Configure(...)`.
+
+```csharp C#
+using System.Collections.Generic;
+using UnityEngine;
+using Superwall;
+
+public sealed class SuperwallEvents : MonoBehaviour, ISuperwallDelegate
+{
+ private void Start()
+ {
+ Superwall.Shared.SetDelegate(this);
+ }
+
+ public void SubscriptionStatusDidChange(SubscriptionStatus from, SubscriptionStatus to)
+ {
+ Debug.Log($"Subscription: {from.Type} -> {to.Type}");
+ }
+
+ public void HandleSuperwallEvent(SuperwallEventInfo eventInfo)
+ {
+ Debug.Log($"Superwall event: {eventInfo.EventType}");
+ }
+
+ public void HandleCustomPaywallAction(string name)
+ {
+ Debug.Log($"Custom action: {name}");
+ }
+
+ public void WillPresentPaywall(PaywallInfo paywallInfo) { }
+ public void DidPresentPaywall(PaywallInfo paywallInfo) { }
+ public void WillDismissPaywall(PaywallInfo paywallInfo) { }
+ public void DidDismissPaywall(PaywallInfo paywallInfo) { }
+
+ public void PaywallWillOpenURL(string url)
+ {
+ Application.OpenURL(url);
+ }
+
+ public void PaywallWillOpenDeepLink(string url)
+ {
+ Application.OpenURL(url);
+ }
+
+ public void HandleLog(
+ string level,
+ string scope,
+ string message,
+ Dictionary info,
+ string error
+ )
+ {
+ if (level == "error")
+ {
+ Debug.LogError($"[Superwall] {scope}: {message} {error}");
+ }
+ }
+
+ public void WillRedeemLink() { }
+ public void DidRedeemLink(RedemptionResult result) { }
+
+ public void HandleSuperwallDeepLink(
+ string fullURL,
+ List pathComponents,
+ Dictionary queryParameters
+ ) { }
+
+ public void CustomerInfoDidChange(CustomerInfo from, CustomerInfo to) { }
+ public void UserAttributesDidChange(Dictionary newAttributes) { }
+}
+```
+
+## Custom Paywall Actions
+
+Use custom actions when a paywall button should trigger game-specific behavior instead of a
+purchase, restore, or close action.
+
+```csharp C#
+public void HandleCustomPaywallAction(string name)
+{
+ if (name == "open_level_preview")
+ {
+ OpenLevelPreview();
+ }
+}
+```
+
+## Removing the Delegate
+
+Set the delegate to `null` when the object should no longer receive callbacks.
+
+```csharp C#
+Superwall.Shared.SetDelegate(null);
+```
diff --git a/content/docs/unity/index.mdx b/content/docs/unity/index.mdx
new file mode 100644
index 0000000..598d6c0
--- /dev/null
+++ b/content/docs/unity/index.mdx
@@ -0,0 +1,61 @@
+---
+title: "Welcome"
+description: "Welcome to the Superwall Unity SDK beta documentation."
+---
+
+
+ The Unity SDK is in beta. APIs, platform requirements, and package behavior may change before a
+ stable release.
+
+
+The Superwall Unity SDK lets Unity mobile games present Superwall paywalls on iOS and Android. It is
+a Unity package with a C# API that bridges to the native [Superwall iOS SDK](https://github.com/superwall/Superwall-iOS)
+and [Superwall Android SDK](https://github.com/superwall/Superwall-Android).
+
+## Quick Links
+
+
+
+ Add the beta package through Unity Package Manager.
+
+
+ Configure the SDK once when your game starts.
+
+
+ Register placements from C# and unlock game features.
+
+
+ Enable controller-aware paywall actions for mobile games.
+
+
+ Review the beta C# API surface.
+
+
+ View the Unity package source.
+
+
+
+## How It Works
+
+The package exposes a `Superwall` C# namespace for Unity scripts. At runtime:
+
+1. Your game calls `Superwall.Configure(...)` once with a Superwall Public API Key.
+2. The Unity package creates a persistent `SuperwallBridge` GameObject for callbacks.
+3. C# calls are forwarded to native iOS or Android bridge code.
+4. The native Superwall SDK fetches campaigns, evaluates placements on device, presents the paywall, and returns callbacks to Unity.
+5. Your C# `feature` callback runs when the user has access.
+
+On iOS, the package's post-build processor adds `SuperwallKit` to the generated Xcode project through CocoaPods. On Android, the package includes a Gradle `.androidlib` module that pulls the Superwall Android SDK and Google Play Billing dependencies.
+
+## Requirements
+
+- Unity 6+ (`6000.4+`)
+- iOS 16.0+
+- Android `minSdkVersion` 25+
+- CocoaPods for iOS builds
+- A Superwall project with mobile app credentials and at least one placement
+
+
+ The Unity Editor uses stubbed native calls and logs method names. Test paywall presentation,
+ purchases, and native callbacks on an iOS or Android build.
+
diff --git a/content/docs/unity/meta.json b/content/docs/unity/meta.json
new file mode 100644
index 0000000..b7b3efc
--- /dev/null
+++ b/content/docs/unity/meta.json
@@ -0,0 +1,27 @@
+{
+ "title": "Unity SDK",
+ "description": "Beta",
+ "icon": "Puzzle",
+ "root": true,
+ "pages": [
+ "index",
+ "changelog",
+
+ "---Quickstart---",
+ "quickstart/install",
+ "quickstart/configure",
+ "quickstart/present-paywalls",
+ "quickstart/user-management",
+ "quickstart/tracking-subscription-state",
+
+ "---Guides---",
+ "guides/game-controller-input",
+ "guides/using-superwall-delegate",
+ "guides/custom-purchase-controller",
+ "guides/advanced-configuration",
+
+ "---SDK Reference---",
+ "sdk-reference/index",
+ "[GitHub Repository](https://github.com/superwall/Superwall-Unity)"
+ ]
+}
diff --git a/content/docs/unity/quickstart/configure.mdx b/content/docs/unity/quickstart/configure.mdx
new file mode 100644
index 0000000..34ff41f
--- /dev/null
+++ b/content/docs/unity/quickstart/configure.mdx
@@ -0,0 +1,74 @@
+---
+title: "Configure the SDK"
+description: "Configure Superwall once when your Unity game starts."
+---
+
+Configure Superwall as early as possible in your first scene. A common pattern is to create a
+bootstrap `MonoBehaviour`, attach it to a GameObject in the first scene, and keep that object alive.
+
+```csharp C#
+using UnityEngine;
+using Superwall;
+
+public sealed class SuperwallBootstrap : MonoBehaviour
+{
+ [Header("Superwall API Keys")]
+ [SerializeField] private string iosApiKey = "MY_IOS_PUBLIC_API_KEY";
+ [SerializeField] private string androidApiKey = "MY_ANDROID_PUBLIC_API_KEY";
+
+ private void Awake()
+ {
+ DontDestroyOnLoad(gameObject);
+
+ var apiKey = Application.platform == RuntimePlatform.IPhonePlayer
+ ? iosApiKey
+ : androidApiKey;
+
+ var options = new SuperwallOptions
+ {
+ Logging = new Logging { Level = LogLevel.Warn },
+ Paywalls = new PaywallOptions
+ {
+ ShouldPreload = true,
+ AutomaticallyDismiss = true
+ }
+ };
+
+ Superwall.Configure(apiKey, options: options, completion: result =>
+ {
+ if (result.IsSuccess)
+ {
+ Debug.Log("[Superwall] Configured");
+ return;
+ }
+
+ if (result is ConfigurationResult.FailedResult failed)
+ {
+ Debug.LogError($"[Superwall] Configuration failed: {failed.Error}");
+ }
+ });
+ }
+}
+```
+
+## Public API Keys
+
+Use the **Public API Key** from your Superwall dashboard app settings. If your Unity game ships on
+both iOS and Android, create or use the matching Superwall app for each platform and choose the key
+at runtime.
+
+
+ In the current beta, Android reports configuration failures through `ConfigurationResult`. iOS
+ reports success when the native `SuperwallKit` configuration callback completes.
+
+
+## Configuration Options
+
+`SuperwallOptions` mirrors the native mobile SDK options for paywall behavior, logging, test mode,
+locale, and other advanced settings. See [Advanced Configuration](/unity/guides/advanced-configuration)
+for the full beta option surface.
+
+
+ After configuring Superwall, continue to [Presenting
+ Paywalls](/unity/quickstart/present-paywalls).
+
diff --git a/content/docs/unity/quickstart/install.mdx b/content/docs/unity/quickstart/install.mdx
new file mode 100644
index 0000000..8476a37
--- /dev/null
+++ b/content/docs/unity/quickstart/install.mdx
@@ -0,0 +1,66 @@
+---
+title: "Install the SDK"
+description: "Install the Superwall Unity SDK beta through Unity Package Manager."
+---
+
+## Overview
+
+Install the Unity SDK from the [Superwall-Unity GitHub repository](https://github.com/superwall/Superwall-Unity). The beta package name is `com.superwall.sdk`.
+
+## Requirements
+
+- Unity 6+ (`6000.4+`)
+- iOS 16.0+
+- Android `minSdkVersion` 25+
+- CocoaPods installed locally for iOS builds
+
+## Add the Package
+
+In Unity, open **Window > Package Manager**. Click **+**, choose **Add package from git URL**, then paste:
+
+```text
+https://github.com/superwall/Superwall-Unity.git
+```
+
+
+
+After Unity resolves the package, your scripts can import the SDK:
+
+```csharp C#
+using Superwall;
+```
+
+## iOS Build Setup
+
+The package includes an iOS post-build processor. When you build for iOS, it:
+
+1. Creates a `Podfile` if the generated Xcode project does not have one.
+2. Adds `pod 'SuperwallKit', '~> 4.0'` to the `UnityFramework` target.
+3. Sets the iOS deployment target to `16.0`.
+4. Runs `pod install` in the generated Xcode project directory.
+
+If `pod install` fails, run it manually in the generated Xcode project folder and reopen the `.xcworkspace`.
+
+
+ If your Unity project already customizes the generated `Podfile`, make sure the `UnityFramework`
+ target includes the `SuperwallKit` pod.
+
+
+## Android Build Setup
+
+No manual Android SDK setup is required for the default Unity Gradle export. The package includes a
+Gradle `.androidlib` module that declares the Superwall paywall activities and pulls:
+
+- `com.superwall.sdk:superwall-android:2.+`
+- Google Play Billing `8.0.0`
+- Material Components `1.12.0`
+- Kotlin coroutines for Android `1.9.0`
+
+The included Android manifest adds the internet, network state, notification, and Google Play Billing permissions, plus the Superwall paywall and debug activities.
+
+
+ If your project uses custom Gradle templates, keep `google()` and `mavenCentral()` enabled and do
+ not remove the generated Superwall `.androidlib` dependency.
+
+
+After installing, continue to [Configure the SDK](/unity/quickstart/configure).
diff --git a/content/docs/unity/quickstart/present-paywalls.mdx b/content/docs/unity/quickstart/present-paywalls.mdx
new file mode 100644
index 0000000..9069282
--- /dev/null
+++ b/content/docs/unity/quickstart/present-paywalls.mdx
@@ -0,0 +1,111 @@
+---
+title: "Presenting Paywalls"
+description: "Register Superwall placements from Unity C# scripts."
+---
+
+Placements are the main way to present paywalls. [Create a placement](/dashboard/dashboard-campaigns/campaigns-placements#adding-a-placement)
+in the Superwall dashboard, add it to a campaign, then register the same placement name from your
+Unity code.
+
+## Register a Placement
+
+Call `RegisterPlacement` when the user tries to access a feature that may be paywalled.
+
+```csharp C#
+using System.Collections.Generic;
+using UnityEngine;
+using Superwall;
+
+public sealed class LevelGate : MonoBehaviour
+{
+ [SerializeField] private int levelNumber = 3;
+
+ public void OnStartLevelPressed()
+ {
+ var handler = new PaywallPresentationHandler
+ {
+ OnPresent = info =>
+ {
+ Debug.Log($"Paywall presented: {info.Name}");
+ },
+ OnDismiss = (info, result) =>
+ {
+ Debug.Log($"Paywall dismissed: {result.Type}");
+ },
+ OnError = error =>
+ {
+ Debug.LogError($"Paywall error: {error}");
+ },
+ OnSkip = reason =>
+ {
+ Debug.Log($"Paywall skipped: {reason}");
+ }
+ };
+
+ Superwall.Shared.RegisterPlacement(
+ "start_level",
+ parameters: new Dictionary
+ {
+ { "level", levelNumber },
+ { "source", "level_select" }
+ },
+ handler: handler,
+ feature: StartLevel
+ );
+ }
+
+ private void StartLevel()
+ {
+ Debug.Log("Feature unlocked");
+ // Load the premium level, award the item, start the mode, etc.
+ }
+}
+```
+
+## When the `feature` Callback Runs
+
+Superwall decides whether the placement should show a paywall based on the campaign configuration
+downloaded at app start.
+
+The `feature` callback runs when the user has access:
+
+- The user already has an active subscription.
+- The user purchases or restores from a gated paywall.
+- The paywall is configured as non-gated.
+- No paywall is configured for the placement.
+
+If a gated paywall is dismissed without a purchase or restore, the `feature` callback does not run.
+
+## Check the Presentation Result
+
+Use `GetPresentationResult` when you need to inspect what Superwall would do for a placement without
+presenting it. In games, this is useful for keeping unlockable UI in sync with your dashboard
+configuration, such as showing lock icons on levels, dimming premium cosmetics, or adding an upgrade
+badge to a game mode before the player taps it.
+
+```csharp C#
+Superwall.Shared.GetPresentationResult("start_level", completion: result =>
+{
+ switch (result.Type)
+ {
+ case PresentationResult.ResultType.Paywall:
+ Debug.Log("A paywall is available for this placement.");
+ break;
+ case PresentationResult.ResultType.Holdout:
+ Debug.Log("The user is in a holdout.");
+ break;
+ case PresentationResult.ResultType.NoAudienceMatch:
+ Debug.Log("No audience matched.");
+ break;
+ case PresentationResult.ResultType.PlacementNotFound:
+ Debug.LogWarning("Placement was not found in the dashboard.");
+ break;
+ }
+});
+```
+
+
+ `GetPresentationResult` uses the same campaign and audience logic that would decide whether a
+ paywall appears. Use it to render upsell UI ahead of time, then call `RegisterPlacement` when the
+ player actually tries to unlock or start the gated content.
+
diff --git a/content/docs/unity/quickstart/tracking-subscription-state.mdx b/content/docs/unity/quickstart/tracking-subscription-state.mdx
new file mode 100644
index 0000000..aa71b16
--- /dev/null
+++ b/content/docs/unity/quickstart/tracking-subscription-state.mdx
@@ -0,0 +1,85 @@
+---
+title: "Tracking Subscription State"
+description: "Read or set subscription status from a Unity game."
+---
+
+If you do not pass a custom purchase controller, Superwall uses the native iOS and Android SDKs to
+manage purchases and subscription-related state.
+
+## Read Subscription Status
+
+```csharp C#
+using Superwall;
+
+var status = Superwall.Shared.SubscriptionStatus;
+
+if (status.Type == SubscriptionStatus.StatusType.Active)
+{
+ var active = (SubscriptionStatus.ActiveStatus)status;
+ Debug.Log($"Active entitlements: {active.Entitlements.Count}");
+}
+```
+
+You can also fetch customer info asynchronously:
+
+```csharp C#
+Superwall.Shared.GetCustomerInfo(info =>
+{
+ Debug.Log($"Customer: {info.UserId}");
+ Debug.Log($"Entitlements: {info.Entitlements.Count}");
+});
+```
+
+## Set Subscription Status Manually
+
+Set subscription status manually when another purchase system is the source of truth for access. In
+a complete custom purchase integration, configure Superwall with an
+[`IPurchaseController`](/unity/guides/custom-purchase-controller) so paywall purchase and restore
+actions are routed to your purchase code, then update `SubscriptionStatus` whenever the player's
+entitlements change.
+
+
+ If you are using Superwall-managed purchases, do not set `SubscriptionStatus` directly. The native
+ iOS and Android SDKs update it automatically after purchases, restores, and receipt checks.
+
+
+```csharp C#
+using System.Collections.Generic;
+using Superwall;
+
+var entitlements = new List
+{
+ new Entitlement
+ {
+ Id = "pro",
+ IsActive = true,
+ Type = EntitlementType.ServiceLevel
+ }
+};
+
+Superwall.Shared.SubscriptionStatus = SubscriptionStatus.CreateActive(entitlements);
+```
+
+Set the status to inactive when the player loses access:
+
+```csharp C#
+Superwall.Shared.SubscriptionStatus = SubscriptionStatus.CreateInactive();
+```
+
+## Listen for Changes
+
+Implement `ISuperwallDelegate` when you need callbacks for subscription or customer changes.
+
+```csharp C#
+public void SubscriptionStatusDidChange(SubscriptionStatus from, SubscriptionStatus to)
+{
+ Debug.Log($"Subscription status changed: {from.Type} -> {to.Type}");
+}
+
+public void CustomerInfoDidChange(CustomerInfo from, CustomerInfo to)
+{
+ Debug.Log($"Customer info changed for {to.UserId}");
+}
+```
+
+See [Using the Superwall Delegate](/unity/guides/using-superwall-delegate) for setup.
diff --git a/content/docs/unity/quickstart/user-management.mdx b/content/docs/unity/quickstart/user-management.mdx
new file mode 100644
index 0000000..cb74060
--- /dev/null
+++ b/content/docs/unity/quickstart/user-management.mdx
@@ -0,0 +1,73 @@
+---
+title: "User Management"
+description: "Identify, reset, and attach attributes to Unity players."
+---
+
+Superwall starts with an anonymous user ID. Identify players after login or account creation so
+paywall assignments and analytics follow the same user across devices.
+
+## Identify a User
+
+```csharp C#
+using Superwall;
+
+public void OnLoginComplete(string userId)
+{
+ Superwall.Shared.Identify(userId);
+}
+```
+
+If you want Superwall to restore paywall assignments after identifying the user, pass
+`IdentityOptions`.
+
+```csharp C#
+Superwall.Shared.Identify(
+ "user_123",
+ new IdentityOptions { RestorePaywallAssignments = true }
+);
+```
+
+## Reset on Logout
+
+Call `Reset` when the player logs out.
+
+```csharp C#
+public void OnLogout()
+{
+ Superwall.Shared.Reset();
+}
+```
+
+## Set User Attributes
+
+Use attributes to target audiences and personalize paywalls.
+
+```csharp C#
+using System.Collections.Generic;
+using Superwall;
+
+Superwall.Shared.SetUserAttributes(new Dictionary
+{
+ { "player_level", 42 },
+ { "guild_id", "north_star" },
+ { "completed_tutorial", true }
+});
+```
+
+You can read the current attributes from Unity:
+
+```csharp C#
+var attributes = Superwall.Shared.GetUserAttributes();
+```
+
+## Read Identity State
+
+```csharp C#
+var userId = Superwall.Shared.UserId;
+var isLoggedIn = Superwall.Shared.IsLoggedIn;
+```
+
+
+ Avoid sending personally identifiable information as plain user attributes unless your privacy
+ policy and data processing setup allow it.
+
diff --git a/content/docs/unity/sdk-reference/index.mdx b/content/docs/unity/sdk-reference/index.mdx
new file mode 100644
index 0000000..5f64a87
--- /dev/null
+++ b/content/docs/unity/sdk-reference/index.mdx
@@ -0,0 +1,175 @@
+---
+title: "SDK Reference"
+description: "Reference for the Superwall Unity SDK beta C# API."
+---
+
+The Unity SDK exposes the `Superwall` namespace. Configure the SDK once with the static
+`Superwall.Configure(...)` method, then use `Superwall.Shared` for placement registration, user
+management, subscription state, and paywall utilities.
+
+## `Superwall.Configure`
+
+```csharp C#
+public static Superwall Configure(
+ string apiKey,
+ SuperwallOptions options = null,
+ IPurchaseController purchaseController = null,
+ Action completion = null
+)
+```
+
+",
+ description: "Optional callback invoked after native configuration completes.",
+ default: "null",
+ },
+ }}
+/>
+
+## `RegisterPlacement`
+
+```csharp C#
+public void RegisterPlacement(
+ string placement,
+ Dictionary parameters = null,
+ PaywallPresentationHandler handler = null,
+ Action feature = null
+)
+```
+
+",
+ description: "Optional placement parameters for audience filters and paywall variables.",
+ default: "null",
+ },
+ handler: {
+ type: "PaywallPresentationHandler",
+ description:
+ "Optional callbacks for paywall presentation, dismissal, errors, skips, and custom callbacks.",
+ default: "null",
+ },
+ feature: {
+ type: "Action",
+ description: "Callback that runs when the user has access to the feature.",
+ default: "null",
+ },
+ }}
+/>
+
+## Common Methods and Properties
+
+ attributes)",
+ description: "Sets user attributes for targeting and personalization.",
+ },
+ SubscriptionStatus: {
+ type: "SubscriptionStatus",
+ description: "Gets or sets the current subscription status.",
+ },
+ GetCustomerInfo: {
+ type: "void GetCustomerInfo(Action completion)",
+ description: "Fetches customer info asynchronously.",
+ },
+ GetPresentationResult: {
+ type: "void GetPresentationResult(string placement, Dictionary parameters = null, Action completion = null)",
+ description: "Checks what Superwall would do for a placement without presenting it.",
+ },
+ PreloadAllPaywalls: {
+ type: "void PreloadAllPaywalls()",
+ description: "Preloads all paywalls from the current configuration.",
+ },
+ PreloadPaywallsForPlacements: {
+ type: "void PreloadPaywallsForPlacements(List placementNames)",
+ description: "Preloads paywalls for the provided placement names.",
+ },
+ HandleDeepLink: {
+ type: "bool HandleDeepLink(string url)",
+ description: "Passes a URL to the native SDK for deep link handling.",
+ },
+ Dismiss: {
+ type: "void Dismiss()",
+ description: "Dismisses the currently presented paywall.",
+ },
+ Purchase: {
+ type: "void Purchase(string productId, Action completion)",
+ description: "Purchases a product directly without presenting a paywall.",
+ },
+ GetProducts: {
+ type: "void GetProducts(List productIds, Action> completion)",
+ description: "Fetches store product details by product ID.",
+ },
+ RefreshConfiguration: {
+ type: "void RefreshConfiguration()",
+ description: "Forces a configuration refresh.",
+ },
+ IsConfigured: {
+ type: "bool",
+ description: "Whether the native SDK is configured.",
+ },
+ IsPaywallPresented: {
+ type: "bool",
+ description: "Whether a paywall is currently presented.",
+ },
+ }}
+/>
+
+## Presentation Handler
+
+```csharp C#
+public class PaywallPresentationHandler
+{
+ public Action OnPresent;
+ public Action OnDismiss;
+ public Action OnError;
+ public Action OnSkip;
+ public Func OnCustomCallback;
+}
+```
+
+## Related Guides
+
+- [Install the SDK](/unity/quickstart/install)
+- [Configure the SDK](/unity/quickstart/configure)
+- [Presenting Paywalls](/unity/quickstart/present-paywalls)
+- [Advanced Configuration](/unity/guides/advanced-configuration)
+- [Custom Purchase Controller](/unity/guides/custom-purchase-controller)
diff --git a/src/lib/llms.ts b/src/lib/llms.ts
index 180be1b..6090775 100644
--- a/src/lib/llms.ts
+++ b/src/lib/llms.ts
@@ -19,6 +19,10 @@ export const llmsSectionConfigs = {
label: "Expo",
urlPrefix: "/docs/expo",
},
+ unity: {
+ label: "Unity",
+ urlPrefix: "/docs/unity",
+ },
"react-native": {
label: "React Native",
urlPrefix: "/docs/react-native",
@@ -62,6 +66,7 @@ function getExamplePathForSection(section: string): string {
android: "/docs/android/guides/advanced/game-controller-support.md",
flutter: "/docs/flutter/guides/advanced/game-controller-support.md",
expo: "/docs/expo/guides/advanced/game-controller-support.md",
+ unity: "/docs/unity/guides/game-controller-input.md",
"react-native": "/docs/react-native/guides/advanced/game-controller-support.md",
dashboard: "/docs/dashboard/dashboard-settings/overview-settings-apple-search-ads.md",
integrations: "/docs/integrations/amplitude.md",
@@ -77,7 +82,7 @@ export function buildLLMSummaryTextFromPages(pages: LLMPageLike[], section?: str
// Add Superwall description
lines.push(
- "Superwall is a platform for remotely configuring and A/B testing mobile app paywalls — no app update required. It provides SDKs for iOS, Android, Flutter, Expo, and React Native, plus a dashboard for managing paywall presentation, experiments, and subscription analytics.",
+ "Superwall is a platform for remotely configuring and A/B testing mobile app paywalls — no app update required. It provides SDKs for iOS, Android, Flutter, Expo, Unity, and React Native, plus a dashboard for managing paywall presentation, experiments, and subscription analytics.",
"",
);
diff --git a/src/lib/sitemap.ts b/src/lib/sitemap.ts
index cf7293d..fa2ac21 100644
--- a/src/lib/sitemap.ts
+++ b/src/lib/sitemap.ts
@@ -38,6 +38,7 @@ export function getSitemapEntries(pagePaths: string[], now = new Date()): Sitema
toSitemapEntry("/android", 0.9, nowIso),
toSitemapEntry("/flutter", 0.9, nowIso),
toSitemapEntry("/expo", 0.9, nowIso),
+ toSitemapEntry("/unity", 0.9, nowIso),
];
const pageEntries = pagePaths.map((pagePath) => toSitemapEntry(pagePath, 0.8, nowIso));
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index 075d14c..4cb29e6 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -155,6 +155,12 @@ const sdkCards: DocCard[] = [
href: buildDocsPath("flutter"),
icon: ,
},
+ {
+ title: "Unity (Beta)",
+ description: "Integrate Superwall into your Unity mobile game.",
+ href: buildDocsPath("unity"),
+ icon: ,
+ },
{
title: "React Native (Legacy)",
description: "Legacy SDK for React Native. Migrate to the Expo SDK for new projects.",