> For the complete documentation index, see [llms.txt](https://docs.coda.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.coda.co/coda-links/redirecting-users-from-coda-links-back-to-your-app.md).

# Redirecting users from Coda Links back to your app

## Guide for iOS App

If you are redirecting users from Coda Links back to your iOS App, please refer to the guide below for the optimal setup.

### Option 1 (Recommended): Set up a [Universal Link](https://developer.apple.com/documentation/xcode/allowing-apps-and-websites-to-link-to-your-content/)

{% hint style="info" %}
**Summary of requirements:**

To support universal links you need to:

1. Create a two-way association between your app and your website and specify the URLs that your app handles, as described in [Supporting associated domains](https://developer.apple.com/documentation/xcode/supporting-associated-domains).
2. Update your app delegate to respond to the user activity object the system provides when a universal link routes to your app, as described in [Supporting universal links in your app](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app).
   {% endhint %}

#### Step 1: Enable Associated Domains in your Apple Developer account

1. In Apple Developer, create or edit your App Identifier and **enable Associated Domains**.
2. Note your **Team ID** and **Bundle ID** — together they form the **App ID** you will declare in the next step in `apple-app-site-association` file

#### Step 2: Create and host `apple-app-site-association` file in your website domain

{% hint style="info" %}
*This file enables iOS to identify the redirect URL as a Universal Link, allowing your app to open automatically post-checkout. Without it, users will encounter a confirmation dialog, asking if they wish to open the app.*
{% endhint %}

1. Define the file content using your App ID (Team ID + Bundle ID) and the URL paths you want to use in your redirect URL. \
   \
   For example, you want to have 2 URL paths to handle back-to-app landing for payment success and payment pending scenarios separately, namely: `https://<your-domain>/payments/success` and `https://<your-domain>/payments/pending` , then your file content should be as follows:

<pre class="language-json"><code class="lang-json"><strong>{
</strong><strong>  "applinks": {
</strong>    "details": [
      {
        "appIDs": ["KV7GMR96XX.com.coda.outlinkdemo"],
        "components": [
          { "/": "/payments/success", "?", "*", "comment": "Match success redirect URL" },
          { "/": "/payments/pending", "?", "*", "comment": "Match pending redirect URL" }
        ]
      }
    ]
  }
}
</code></pre>

2. Save the file is saved exactly as `apple-app-site-association` **(without an extension)**
3. Place it in your site’s `.well-known` directory, and make sure it is public. The file’s URL should match the following format:&#x20;

   ```
   https://<your-domain>/.well-known/apple-app-site-association
   ```

{% hint style="warning" %}
**Important Notes:**&#x20;

* Ensure the file does NOT have a `.json` extension. But it must be served with the `application/json` MIME type. To verify the MIME type, you can use the following command:

```
curl -I https://<your-domain>/.well-known/apple-app-site-association
```

* You must host the file using https\:// with a valid certificate and with no redirects.
  {% endhint %}

#### Step 3: **Add Associated Domains entitlements in Xcode:**&#x20;

In ***Signing & Capabilities tab*** in Xcode, add ***Associated Domains*** capability:

<figure><img src="/files/UJ8mhQpMIAODCu7q8VYQ" alt="" width="563"><figcaption></figcaption></figure>

Then, click **+** to register your domain with the `applinks:` prefix, such as:

<pre><code><strong>applinks:&#x3C;your-domain>
</strong></code></pre>

For full instructions, refer to Apple's page [here](https://developer.apple.com/documentation/xcode/supporting-associated-domains#Add-the-associated-domains-entitlement-to-your-app)

#### Step 4: Provide the Universal Links to Coda

**If you are using Coda Links to Coda-hosted Payment Page**: you can set the Universal Links you have successfully configured in Coda Portal, and Coda Links will redirect your users there automatically

<figure><img src="/files/VasOaOFlL7JECYbO66Vj" alt="" width="375"><figcaption></figcaption></figure>

**If you are using Coda Links to Coda Webstore**: please reach out to your Account Manager or our Technical Support team (<partnersupport@coda.co>) to provide the Universal Links. We will help you set them up in your Webstore.

#### Step 5: Handle Universal Links in your app

Now you can add instructions in your app to display the right screen to the user when they open the Universal Links. For example, when user lands with `https://<your-domain>/payments/success` , you can grant them the in-game item and display a purchase success screen with confetti animations!

### Option 2 (Not recommended): Set up a Custom URL Scheme

{% hint style="danger" %}
Use only this approach when Universal Links cannot be used. Behaviour is undefined if multiple apps register the same scheme.

Universal Links are always recommended for a smoother experience.
{% endhint %}

#### Step 1: Register the URL scheme in Info.plist

Add your custom scheme under `CFBundleURLTypes`&#x20;

Example:

```xml
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>com.yourcompany.yourapp</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <!-- Make sure the scheme is unique -->
      <string>coda</string>
    </array>
    <key>CFBundleURLHosts</key>
    <array>
      <string>yourapp.yourcompany.com</string>
    </array>
  </dict>
</array>
```

#### Step 2: Handle the scheme in the app

<details>

<summary>AppDelegate (iOS ≤12)</summary>

```swift
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  func application(_ app: UIApplication,
                   open url: URL,
                   options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    // Handle custom scheme URL
    handleCustomSchemeURL(url)
    return true
  }

  private func handleCustomSchemeURL(_ url: URL) {
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
      print("❌ Failed to parse custom scheme URL")
      return
    }

    // Parse the URL to extract payment status
    if let status = components.queryItems?.first(where: { $0.name == "status" })?.value {
      handlePaymentStatus(status: status)
    }
  }

  private func handlePaymentStatus(_ status: String) {
    // Post notification for view controllers to handle
    let notificationName: Notification.Name
    switch status.lowercased() {
    case "success": notificationName = .paymentSuccess
    case "failure": notificationName = .paymentFailure
    default:
      print("⚠ Unknown payment status: \(status)")
      return
    }

    DispatchQueue.main.async {
      NotificationCenter.default.post(name: notificationName, object: nil)
    }
  }
}

extension Notification.Name {
  static let paymentSuccess = Notification.Name("PaymentSuccess")
  static let paymentFailure = Notification.Name("PaymentFailure")
}

```

</details>

<details>

<summary>SceneDelegate (iOS 13+)</summary>

```swift
import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  var window: UIWindow?

  func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let urlContext = URLContexts.first else { return }
    let url = urlContext.url
    handleCustomSchemeURL(url)
  }

  private func handleCustomSchemeURL(_ url: URL) {
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
      print("❌ Failed to parse custom scheme URL")
      return
    }

    if let status = components.queryItems?.first(where: { $0.name == "status" })?.value {
      handlePaymentStatus(status: status)
    }
  }

  private func handlePaymentStatus(_ status: String) {
    let notificationName: Notification.Name
    switch status.lowercased() {
    case "success": notificationName = .paymentSuccess
    case "failure": notificationName = .paymentFailure
    default:
      print("⚠ Unknown payment status: \(status)")
      return
    }

    DispatchQueue.main.async {
      NotificationCenter.default.post(name: notificationName, object: nil)
    }
  }
}

```

</details>

<details>

<summary>SwiftUI</summary>

```swift
import SwiftUI

@main
struct MyApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
        .onOpenURL { url in
          handleCustomSchemeURL(url)
        }
    }
  }

  private func handleCustomSchemeURL(_ url: URL) {
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
      print("❌ Failed to parse custom scheme URL")
      return
    }

    if let status = components.queryItems?.first(where: { $0.name == "status" })?.value {
      handlePaymentStatus(status: status)
    }
  }

  private func handlePaymentStatus(_ status: String) {
    let notificationName: Notification.Name
    switch status.lowercased() {
    case "success": notificationName = .paymentSuccess
    case "failure": notificationName = .paymentFailure
    default:
      print("⚠ Unknown payment status: \(status)")
      return
    }

    DispatchQueue.main.async {
      NotificationCenter.default.post(name: notificationName, object: nil)
    }
  }
}

```

</details>

{% hint style="danger" %}
**Security Considerations**

* **Do not trust redirect URLs alone.** They can be forged. Always cross-check payment status with your backend using webhook or inquiry
* **Validate all incoming URLs.** Ensure they come from your expected domain (for Universal Links) or your registered scheme (for custom URLs)
* **Universal Links are safer than custom schemes.** They verify domain ownership and prevent interception by other apps
  {% endhint %}

## Guide for Android App

If you are working on redirecting users from Coda Links back to your Android App, please refer to the guide below for the optimal setup.

{% hint style="warning" %}
UNDER CONSTRUCTION
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.coda.co/coda-links/redirecting-users-from-coda-links-back-to-your-app.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
