> ## Documentation Index
> Fetch the complete documentation index at: https://docs.startale.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deep linking

> Link directly to a specific screen inside your Mini App with /miniapps#<appId><relativeUrl>, resolved same-origin against your home URL.

A Mini App deep link is a URL on `app.startale.com` that opens your Mini App directly, no feed or preview card involved. Typed in a browser, tapped from a Missions CTA, or shared in a chat, it loads the Startale App straight to your Mini App.

```
https://app.startale.com/miniapps#<appId><relativeUrl>
```

## Format

| Part          | Required | Description                                                                                                       |
| ------------- | -------- | ----------------------------------------------------------------------------------------------------------------- |
| `appId`       | Yes      | Your Mini App's canonical id, assigned by the Startale team. See [Getting your app id](#getting-your-app-id).     |
| `relativeUrl` | No       | A path (`/...`), a query (`?...`), or both, resolved against your Mini App's home URL. Anything else is rejected. |

```
#co-nft                              → opens CoNFT at its home screen
#co-nft/collection/0x41be52...       → opens CoNFT at that collection
#elhexa/tokens/123?ref=x             → opens ELHEXA at /tokens/123 with ?ref=x
#elhexa?tab=1                        → opens ELHEXA at its home path with ?tab=1
```

`appId` is read up to the first `/` or `?` in the fragment; everything from that character on is `relativeUrl`, passed through unmodified (including its own nested `/` or `?` characters, e.g. `?path=/a/b`).

## Resolving the target

`relativeUrl` is resolved against your Mini App's home URL, not treated as a full URL:

* **A path (`/...`) resolves under your home's base path.** If your home URL is `https://your-app.com/x`, `/collections/123` resolves to `https://your-app.com/x/collections/123`. The base path is always kept, it is never replaced.
* **A query (`?...`) leaves the path untouched** and only affects the query string.
* **Your home URL's own query params are preserved.** If your home URL is `https://your-app.com/?lang=ja`, a deep link to `/tokens/1` resolves to `https://your-app.com/tokens/1?lang=ja`.
* **A deep-link param wins on key collision.** `?lang=en` against a home URL of `https://your-app.com/?lang=ja` resolves to `?lang=en`, not both.
* **Resolution uses the viewer's own edition of your home URL.** If your manifest declares a `jpUrl`, a Japan-edition viewer resolves `relativeUrl` against `jpUrl` (base path and query included); a Global-edition viewer resolves it against your default `homeUrl`. The same shared link produces the correct edition-specific URL for whoever opens it, you do not need separate deep links per edition.

<Note>
  **Only `/...` or `?...` is accepted.** A bare `foo/bar` is rejected (it would resolve as a *sibling* of your home path under standard URL parent-directory rules, not a child of it) and the deep link opens your Mini App's home instead. Always start `relativeUrl` with `/` or `?`.
</Note>

## Security: same-origin only

A deep link can never point your Mini App's iframe at a different origin. The relative URL is rejected (falls back to home) if it would:

* Resolve to a different origin than your home URL (`https://evil.com/...`, `//evil.com/...`, and other Startale App browser origin-confusion payloads such as `/\evil.com` all fail this check).
* Escape your home's base path via `..` (e.g. `/../secret` against a home path of `/x`).
* Fail to parse as a URL at all.

This is enforced twice, independently: once when the deep link is resolved, and again as a backstop when the resolved URL is handed to the iframe. There is no path through the deep-link format that can navigate your Mini App off its own origin.

## Getting your app id

You do not choose your Mini App's `appId`. It is assigned by the Startale team when your Mini App is registered, as part of onboarding, alongside your referral code. See [Submission](/miniapps/submission) for how a Mini App gets listed.

<Warning>
  **An unregistered or misspelled `appId` opens nothing.** The Startale App matches `appId` against its own catalog of listed Mini Apps. If there's no match, the deep link falls through with no app opening at all, not an error page. Double-check the id you were given if a deep link isn't working.
</Warning>

If your project is later renamed, reach out to the Startale team rather than assuming your existing deep links keep working under a new id; legacy ids are kept working only where an alias has been explicitly set up for that rename.

## Deep links and notification tap destinations

Notifications V1's `targetUrl` (see [Notifications](/miniapps/notifications#sending-a-notification)) also lands a tap on a specific screen in your Mini App, but it does not go through this page's format. The two only intersect in one narrow case:

* **With a valid, same-origin `targetUrl`**: tapping **Open Mini App** opens your Mini App inline, right on the notifications screen, loaded directly at that absolute URL. This never touches `#appId<relativeUrl>` at all, it's a structurally separate code path.
* **Without a `targetUrl`** (not set, or its origin doesn't match your registered home URL): tapping **Open Mini App** navigates to `#appId`, this page's format, but always in its plain, **home-only** form. There is no `relativeUrl` in this fallback, it cannot land the user on a specific screen, only your home.

|                 | Deep link (`#appId<relativeUrl>`)                                                                          | Notification `targetUrl`                                                      |
| --------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| Format          | `appId` + an optional relative path/query, resolved against your home URL                                  | A full, absolute URL you control end to end                                   |
| Where it's used | Shareable/external links, in-app CTAs, and the no-`targetUrl` notification fallback (home only, see above) | The tap destination of a push notification you send, when set and same-origin |
| Origin check    | Enforced against your registered home URL, on open                                                         | Enforced against your `senderId`, both at send time (NS) and on open          |

Building a `targetUrl` doesn't give you `relativeUrl` support and vice versa: these are two independent mechanisms that happen to both end up rendering inside the same `AppSheet` surface.

## Linking to another Mini App from inside yours

There is no dedicated SDK action for "open a different Mini App," but you can get there today by combining two things that already exist: [`sdk.actions.openUrl`](/miniapps/sdk-actions#actions-openurl) and a deep link. Point `openUrl` at another Mini App's deep link instead of an external URL:

```ts theme={null}
import { sdk } from '@farcaster/miniapp-sdk'

// From inside e.g. Morning Moon Pocket, link to the NFT the user just minted on CoNFT
sdk.actions.openUrl('https://app.startale.com/miniapps#co-nft/collection/0x41be52c22C95D611624d7db2a9A8D277d7cc286d')
```

`openUrl` doesn't treat `app.startale.com` specially, it opens whatever `http(s)` URL you give it in a new browser tab. Because that tab loads the Startale App fresh, the deep link resolves normally on load and the user lands on that exact CoNFT screen. There is no registration or allowlist check on the target beyond what deep linking itself already enforces (the target `appId` must be a registered Mini App, see [Getting your app id](#getting-your-app-id)), so this works for linking to any Mini App, including your own.

<Note>
  **This opens a new tab, it does not hand off in place.** The linking Mini App's own iframe is left running in the background tab; there is currently no "swap to app B, then back to app A where you left off" navigation. If you need that instead of a new tab, talk to the Startale team, it's a different, not-yet-built capability.
</Note>
