🚀 Join the waitlist now! waitlist.floot.dev
LogoFlootdocs

Deep Links

Learn how to set up and customize deep linking for your Floot app.

The scheme

Deep links are already wired for iOS, Android, macOS and Windows. floot create derives the URL scheme from the two things you gave it, and writes it into every platform file for you.

scheme = <org> + . + <project name> with the underscores removed and everything lowercased.

So floot create my_app --org com.acme produces the scheme com.acme.myapp. Without --org the organization defaults to com.example, giving com.example.myapp.

One value is spelled differently

OAUTH_APPLE_CLIENT_ID keeps the capital letter: com.acme.myApp, not com.acme.myapp. It is not a deep-link scheme at all, see the Apple client id below.

Every example below uses the scheme from floot create my_app --org com.acme. Substitute your own.

Where it already is

FileWhat it holds
ios/Runner/Info.plistCFBundleURLSchemes
android/app/src/main/AndroidManifest.xmldata android:scheme
macos/Runner/Info.plistCFBundleURLSchemes
pubspec.yamlmsix_config → protocol_activation
.env.localOAUTH_REDIRECT_URL
supabase/.env.localAPP_URL_SCHEME
supabase/config.tomladditional_redirect_urls

Changing the scheme means changing it in all seven. The sections below show each one.

Scheme customization

Go to ios/Runner/Info.plist → CFBundleURLTypes → CFBundleURLSchemes.

There are two schemes in that array. Edit the second one; the first is your Google reversed client id, which Google Sign-In fills in and which must stay exactly as Google issued it.

ios/Runner/Info.plist
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>your_google_ios_REVERSED_client_id</string>
      <string>com.acme.myapp</string>
    </array>
  </dict>
</array>

Where else the scheme is used

The scheme is not only a platform setting. Three environment values are built from it, and they have to agree with the platform files or the redirect lands nowhere, usually as a browser sitting on a blank page rather than as an error.

The app's OAuth redirect

OAUTH_REDIRECT_URL is always <scheme>://<path>. floot create sets the path to oauth-callback; keep it and change only the scheme.

.env.local
OAUTH_REDIRECT_URL="com.acme.myapp://oauth-callback"

Supabase Auth refuses to redirect anywhere that is not on its allow-list, so the same full URL has to be there too. It already is, as the second entry:

supabase/config.toml
additional_redirect_urls = ["https://127.0.0.1:3000", "com.acme.myapp://oauth-callback"]

config.toml covers your local stack only. On a hosted project the same list lives in the dashboard, under Authentication → URL Configuration → Redirect URLs, and you have to add it there yourself.

Requires ENABLE_STRIPE

Stripe is off in a new project. Set `ENABLE_STRIPE=true` in `supabase/.env.local` to use this section.

APP_URL_SCHEME is the bare scheme, with no path. It is used as the app's URL scheme to bring the user back to <scheme>://payments?... after a checkout or a trip to the billing portal.

supabase/.env.local
APP_URL_SCHEME="com.acme.myapp"

It is optional until ENABLE_STRIPE is on, at which point the Edge Functions refuse to start without it. See Stripe.

The Apple client id

OAUTH_APPLE_CLIENT_ID looks like the scheme but is not one, and it is the one value you must not lowercase:

supabase/.env.local
OAUTH_APPLE_CLIENT_ID="com.acme.myApp"

It is your Apple Services ID, and it has to match the iOS bundle identifier that Flutter generated, where the project name is camel-cased rather than flattened. config.toml reads it straight into [auth.external.apple].client_id, so "correcting" it to match the deep-link scheme breaks Sign in with Apple. See Apple Sign-In.

To act on a link once the app is open, edit openAppLink(...).

lib/core/presentation/views/widgets/deep_link_listener.dart
class _DeepLinkListenerState extends State<DeepLinkListener> {
	...

  void openAppLink(Uri uri) {
    // ...existing code

    // 👇 your handling logic here!
  }

  ...
}

It is called for both entry points: the link that cold-started the app, and any link that arrives while it is already running.

On this page