AI-coded apps

    How do I fix the Rork 'API key not found' error?

    Rork no-code app builder showing an API key not found error and the environment variables panel

    When a Rork build returns 'API key not found' at runtime, the failure is almost always a configuration mismatch between the Rork environment variables panel, the Expo bundler that inlines those values, and the upstream provider that issued the key. The fix is short once the cause is identified, but the error message rarely points at the right layer.

    Short answer

    The 'API key not found' error in Rork almost always means the runtime is reading process.env.YOUR_KEY and getting undefined. In a Rork project built on Expo, only variables prefixed with EXPO_PUBLIC_ are inlined into the JavaScript bundle, per the Expo environment variables guide. Fix the prefix, confirm dot notation in code, rebuild, and the value reappears at runtime.

    What you should know

    • Rork generates Expo and React Native apps. Any rule that applies to Expo environment variables applies to Rork.
    • The EXPO_PUBLIC_ prefix is mandatory for client-side keys. Without it, the variable is not inlined and reads as undefined.
    • process.env.EXPO_PUBLIC_KEY only works with dot notation. Bracket notation like process.env['EXPO_PUBLIC_KEY'] is not replaced during bundling.
    • A Supabase service_role key in a public Rork app is a security incident, not a fix. Use the anon key in client code.
    • Edge functions read secrets from their own scope. Updating a Supabase secret without redeploying the function still serves the old value.
    • Newly issued provider keys can take time to activate. OpenAI and Stripe both publish activation behavior in their authentication documentation.

    Why does Rork return 'API key not found' even though the value is set?

    In practice, the message means the bundled JavaScript read undefined at the call site, not that Rork failed to save the value in the dashboard. According to the Expo environment variables documentation, the Metro bundler performs a static replacement of process.env.EXPO_PUBLIC_KEYNAME with the literal value at build time. Variables without the EXPO_PUBLIC_ prefix are skipped entirely. So when a developer sets OPENAI_API_KEY=sk-... in the Rork Integrations panel and then references process.env.OPENAI_API_KEY in code, the bundler leaves the lookup unresolved and the runtime returns undefined. The provider library catches that and throws the 'API key not found' or 'API key missing' error. The variable is stored in Rork; it just never makes it into the bundle.

    This is also why renaming a variable in the Rork panel fixes the issue immediately for new builds: changing OPENAI_API_KEY to EXPO_PUBLIC_OPENAI_API_KEY and updating the reference in code triggers the Metro bundler to inline the value on the next compile.

    How do I check whether my Rork variable is prefixed correctly?

    Open the Rork Integrations panel, then Environment Variables. Compare your variable name with the table below.

    Variable name in RorkBundled in client app?Where it works
    EXPO_PUBLIC_OPENAI_API_KEYYesReact Native screens
    OPENAI_API_KEY (no prefix)NoOnly inside a backend function
    EXPO_PUBLIC_SUPABASE_ANON_KEYYesSupabase client init in the app
    SUPABASE_SERVICE_ROLE_KEYNo, and must not beEdge function only
    EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEYYesStripe Elements on device
    STRIPE_SECRET_KEYNoEdge function only

    For any key that must be available in the screen code, prefix with EXPO_PUBLIC_. For any key with admin scope (Supabase service_role, Stripe secret key, an OpenAI key that bills your account), keep it out of the bundle and call it only through a backend function. The Supabase API keys documentation is explicit that the anon key is safe for clients and the service_role key is not.

    My key has the right prefix, so why is it still undefined?

    When the prefix is correct, three causes account for most of the remaining cases.

    The first is dot notation. The Expo guide shows that only process.env.EXPO_PUBLIC_X is replaced at build time. process.env['EXPO_PUBLIC_X'] and destructured forms like const { EXPO_PUBLIC_X } = process.env are not. This trips up code generated by an AI prompt that defaulted to bracket access for a dynamic key.

    The second is build caching. After changing a variable in the Rork panel, the bundled output does not refresh until the project is rebuilt. The static inline happens at compile time, so a value added five minutes after the last build is invisible to the running app until a new compile.

    The third is a typo in the variable name. EXPO_PUBLIC_OPEN_AI_KEY and EXPO_PUBLIC_OPENAI_KEY are not interchangeable. The bundler matches the exact string in the source code against the exact string in the variable name.

    How do I fix the error when the call goes through a Supabase edge function?

    When the failing call comes from a Supabase edge function, the variable lives in a different place. Edge functions do not read from Rork environment variables; they read from secrets stored inside the Supabase project. The Supabase edge function secrets documentation explains that a secret is exposed to the function via Deno.env.get('SECRET_NAME').

    The three failure modes here are:

    1. The secret was set in Supabase, but the function was not redeployed. The function bundle locks in environment values at deploy time.
    2. The function reads from process.env.SECRET_NAME instead of Deno.env.get('SECRET_NAME'). Supabase edge functions run on Deno, not Node.
    3. The function was generated by Rork using an old secret name, and the developer later renamed the secret without updating the function code.

    The fix sequence is: confirm the secret exists in the Supabase project, redeploy the function, then re-test the call from the Rork app.

    What about freshly issued OpenAI or Stripe keys that still fail?

    Newly issued provider keys sometimes return 'invalid API key' or 'API key not found' until they propagate. The OpenAI authentication reference notes that a 401 with invalid_api_key can stem from a key that was deleted, revoked, or not yet active. Stripe documents a similar pattern in its API keys reference, with reactivation delays after a rotation.

    For most providers, the practical wait is short, often under an hour. The longer waits, sometimes reported up to two hours, typically apply when an organization has billing or verification holds that have not cleared. If a key still fails after that window, the issue is almost certainly the prefix, the dot notation, or a stale build, not the provider.

    How do I verify the variable is actually reaching my Rork app?

    A targeted log is the fastest verification. In the screen where the API call is made, log the presence (not the value) directly before the call.

    console.log('OpenAI key present:', Boolean(process.env.EXPO_PUBLIC_OPENAI_API_KEY));
    

    If the log prints true, the variable is reaching the bundle and the failure is downstream (wrong key value, wrong provider, billing hold). If it prints false, the variable is not bundled and the issue is one of: prefix missing, dot notation wrong, last build was before the variable was added, or a typo in the name.

    Do not log the value itself. The bundle is shipped to user devices, and any console.log of a real API key is reachable through device tooling. The boolean check is enough.

    What to watch out for

    Three patterns cause repeat regressions in Rork apps.

    The first is treating EXPO_PUBLIC_ keys as private. Any value prefixed with EXPO_PUBLIC_ is embedded in plain text in the compiled APK or IPA, per the Expo security note. A determined user can extract the bundle and read the value. OpenAI keys, Stripe secret keys, and any admin-scope token should be moved behind an edge function and called from the Rork app via a public function URL.

    The second is renaming variables without renaming the code references. Rork's AI editor regenerates code based on prompts, and a 'rename my OpenAI key variable' prompt sometimes updates the panel without rewriting every existing reference. Search the project for the old name before assuming the rename is clean.

    The third is misreading OWASP MASVS guidance. OWASP MASVS-STORAGE-2, per the official MASVS controls, expects that no sensitive data is hardcoded in the app binary. An EXPO_PUBLIC_ variable that wraps a service_role token still fails this check, because the token ends up in the binary after build. For builders who want an external automated read of a compiled build before submission to App Store Connect or Google Play, PTKD.com (https://ptkd.com) is one of the platforms focused on pre-submission OWASP MASVS scanning for no-code and AI-coded apps including those generated by Rork.

    Key takeaways

    • Check the prefix first. Most 'API key not found' errors in Rork resolve to a missing EXPO_PUBLIC_ prefix on the environment variable.
    • Rebuild after every variable change. The Metro bundler inlines values at compile time, not at runtime, so a fresh build is required for any panel edit to take effect.
    • Move admin-scope keys behind an edge function. Anything that bills your account or grants service_role access should never sit in an EXPO_PUBLIC_ variable.
    • Verify with a boolean log, not a value log. Boolean(process.env.EXPO_PUBLIC_X) confirms presence without leaking the key to anyone who extracts the bundle.
    • Some teams outsource the pre-submission scan. Platforms like PTKD.com run automated OWASP MASVS checks on the compiled IPA or AAB, which is one way to catch hardcoded secrets before App Review or Google Play Protect does.
    • #rork
    • #api-keys
    • #expo
    • #environment-variables
    • #no-code
    • #supabase
    • #debugging

    Frequently asked questions

    Where exactly is the 'API key not found' error coming from in my Rork app?
    The error is thrown by the provider SDK after it reads undefined from process.env.YOUR_KEY. Rork passes environment variables to the Expo build process. If the variable has no EXPO_PUBLIC_ prefix, the Metro bundler skips it, the runtime gets undefined, and the provider library raises 'API key not found' or 'API key missing' depending on its message format.
    Can I use a Supabase service_role key in Rork to bypass the not found error?
    No. The service_role key bypasses Row Level Security and is the equivalent of admin access. Once it is inlined into a client bundle via EXPO_PUBLIC_, anyone who downloads the APK or IPA can extract it. Use the anon key in the Rork app and route admin operations through a Supabase edge function that reads the service_role secret from its own scope.
    Why does my key work in the Rork preview but not in the built app?
    The Rork preview and the production build use different bundling steps. A variable added shortly before the preview may not be present in the latest production build manifest. Trigger a fresh build after each environment variable change, then re-test from the production app, not the in-editor preview, before assuming the value is missing.
    Does Rork support secret variables that are not visible in the bundle?
    Not directly in the client app. Anything prefixed with EXPO_PUBLIC_ is inlined into the JavaScript bundle and visible to anyone who extracts the binary. For secrets that must stay private, store them as Supabase edge function secrets or in another backend, and call the function from the Rork screen using only the public function URL.
    How do I know if the issue is the key value or the configuration?
    Run Boolean(process.env.EXPO_PUBLIC_YOUR_KEY) in the screen that fails and check the log. If it prints true, the configuration is correct and the failure is the value, the provider, or billing. If it prints false, the variable never reached the bundle, and you are looking at a prefix, dot notation, or rebuild issue.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free