Supabase Deep Link DoctorTools for workARLing s. r. o., Bratislava

See why the deep link back from Supabase never arrives.

Paste your Flutter and supabase_flutter OAuth or magic-link deep link config. Get the exact scheme, host and file mismatch, and the value to fix, before it costs you another afternoon.

Diagnose yours Source code on GitHub

Free
Every check and every finding, with no account and no limit.
Paid
Nothing. This tool has no paid version and no sign-up.
Limits
Flutter on iOS and Android, behind 94 automated tests.
Your data
Nothing leaves your browser. There is no backend of ours behind this page.
The tool after a diagnosis: a verdict and the rules that fired, each with the file and field it points at.
A real diagnosis of the configuration the tool opens with, run on this page. Nothing was sent to a server of ours; you can repeat it below.
RedirectDoctorFlutter.diagnose(config) client-side, no network
App
AndroidManifest intent-filter
Only meaningful for https Android App Links, not a custom scheme.
Supabase
OAuth provider
Your code
Result: idle
Fill in the form, then press Diagnose.
status idle not run yet

Nothing you type is sent anywhere. The check runs in your browser, using the same allow-list matching rules Supabase documents.

Read-only, client-side analysis. Nothing you enter is sent anywhere: the check runs against the values you type, not your live project. Always verify in your own environment. Not affiliated with Supabase, Google, Apple, GitHub, Discord, Kakao or the Flutter project.

Three reasons your deep link never reaches the app.

Every supabase_flutter team hits the same three walls. Locally they line up by accident. In a release build, on a real device, they don't.

  1. Three files, one string.

    redirectTo, CFBundleURLSchemes, the AndroidManifest intent-filter and the Supabase redirect allow-list are four separate places that must agree on the exact same scheme://host. Miss one and the OS never hands the link back to your app.

  2. An underscore breaks Google sign-in.

    A scheme like my_app://callback looks fine everywhere you check it, until Google's OAuth redirect handling mangles the underscore and Supabase's redirect check always fails (supabase/auth#2447), quietly falling back to Site URL.

  3. The wrong LaunchMode strands the browser.

    LaunchMode.inAppWebView gets detected and blocked by Kakao's, Discord's and Facebook's OAuth screens. Implicit flow puts the session in a URL fragment that deep links don't always preserve. Both leave the user stuck mid-flow.

One function. Config in, diagnosis out.

No server, no SDK key, no signup. doctor-flutter.js is plain JavaScript: read it, fork it, or run it in your own scripts or CI.

import { diagnose } from './doctor-flutter.js';
// or, loaded globally: const { diagnose } = window.RedirectDoctorFlutter;

const result = diagnose({
  app:      { scheme, host, launchMode, authFlowType, iosSchemesInPlist, androidIntentFilter },
  supabase: { projectUrl, siteUrl, allowedRedirectUrls },
  provider: { name, authorizedRedirectUris },
  code:     { redirectTo, usesSkipBrowserRedirect, listensToAuthStateChange },
});

// result
{
  "status":     "fail" | "warn" | "pass",
  "summary":    "...",
  "expected":   { redirectTo, iosPlistScheme, androidIntentFilter, allowListEntry, supabaseCallback },
  "problems":   [ { severity, code, message, where } ],
  "fixes":      [ { title, value, where } ],
  "checklist":  [ "..." ],
  "disclaimer": "..."
}

Everything runs client-side. The form above calls this exact function in your browser. There is no backend, no API key, and no request that carries your config anywhere.

It checks the deep link your app will actually register, computed once from scheme and host, against Info.plist, the AndroidManifest intent-filter, the Supabase redirect allow-list, and the exact callback your OAuth provider console expects.

Free.

No account, no payment, no rate limit. This started as a tool I needed myself. If it saves you an afternoon, tell me what it got wrong: open a GitHub issue.

Questions developers actually search for.

Straight answers to the same supabase_flutter deep link questions this tool diagnoses, for when you just need the answer, not the checker.

Why doesn't Supabase OAuth redirect back to my Flutter app on Android?

The most common cause is a mismatch between the scheme and host your Dart code sends as redirectTo and the android:scheme and android:host values in the AndroidManifest.xml intent-filter. If they don't match exactly, Android has nothing registered to catch the link. The second cause is an underscore in the scheme: Google's OAuth redirect handling mangles underscores, so a scheme like my_app always fails Supabase's redirect-URL check and falls back to Site URL (tracked in supabase/auth#2447).

What redirectTo should I use with supabase_flutter?

Use the exact scheme://host form documented by Supabase, for example io.supabase.myapp://login-callback, with no trailing slash and no path beyond the host. That same string must appear unchanged in four places: the redirectTo argument, the CFBundleURLSchemes entry in Info.plist, the AndroidManifest intent-filter, and the Supabase redirect allow-list.

Does an underscore in my deep link scheme break Google sign-in?

Yes. Supabase's own auth repository documents this as a known issue, supabase/auth#2447. A redirect URL containing an underscore, such as my_app://callback, is mangled by Google's OAuth handling and always fails Supabase's redirect-URL match, falling back to Site URL instead of returning to the app. Use a hyphen instead, my-app://callback, or a dotted reverse-domain scheme like io.supabase.myapp.

Which LaunchMode should I use for signInWithOAuth in Flutter?

Set authScreenLaunchMode: LaunchMode.externalApplication. It opens the provider's OAuth screen in the system browser, which is what hands control back to the OS to fire your app's custom-scheme intent-filter or CFBundleURLSchemes entry. LaunchMode.inAppWebView embeds a WebView instead, and Kakao, Discord and Facebook among others detect that and either refuse to complete sign-in or never trigger the redirect back out.

What goes into Info.plist and AndroidManifest for Supabase deep links?

In ios/Runner/Info.plist, add a CFBundleURLTypes array containing a dict whose CFBundleURLSchemes array lists your scheme. In android/app/src/main/AndroidManifest.xml, add an intent-filter to your launch activity with action VIEW, categories DEFAULT and BROWSABLE, and a data element with android:scheme and android:host matching your redirectTo exactly. Leave android:autoVerify off: it only does anything for https Android App Links.

What redirect URI do I put in the Google console for supabase_flutter?

Google Cloud Console's "Authorized redirect URIs" field needs Supabase's own callback, https://your-project-ref.supabase.co/auth/v1/callback, never your app's custom scheme. Google redirects to Supabase first at that URL, and only then does Supabase redirect on to your Flutter app's scheme://host. Your app's deep link never goes in the provider console.

Who publishes this and how it works.

Publisher
ARLing s. r. o., Ivanská cesta 32E, 821 04 Bratislava, Slovakia. Company number 56583486, VAT ID SK2122352100.
Who makes it
Written and maintained by one person in Bratislava. The source is public on GitHub.
Payment and delivery
Nothing is paid for and nothing is unlocked. The answer appears in the page as soon as the check runs.
Sample and terms
The tool opens with a worked example, so you can see a real result before you paste your own.
Reply
We answer andrej@arling.sk within 24 hours.
What it is not
We are not the vendor whose error you are chasing. The tool reads what you paste and names the rule; it changes nothing on your side.

Terms Privacy