Skip to main content
RapidDev - Software Development Agency
retool-tutorial

Why Is My Retool App Not Loading Data from API?

When a Retool app doesn't load API data, open the Debug Panel (bottom bar) → Queries tab to see the error. Common causes: 401/403 (wrong API key or expired token), CORS error (whitelist Retool's domain or proxy the request through a backend), timeout (API too slow or timeout setting too low), IP blocked (whitelist Retool's IP ranges in the API firewall), or wrong resource configuration (bad base URL, wrong auth type). Each has a specific fix.

What you'll learn

  • Use the Retool Debug Panel's Queries tab to inspect API errors and response payloads
  • Diagnose 401/403 authentication errors caused by missing or expired credentials
  • Identify and resolve CORS errors that block API calls from the Retool domain
  • Fix timeout errors caused by slow API responses or misconfigured timeout thresholds
  • Resolve IP whitelisting issues when the API requires Retool's outbound IP to be allowlisted
  • Check resource configuration for common mistakes: wrong base URL, wrong auth type, missing headers
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read20-30 minRetool Cloud and Self-hostedLast updated March 2026RapidDev Engineering Team
TL;DR

When a Retool app doesn't load API data, open the Debug Panel (bottom bar) → Queries tab to see the error. Common causes: 401/403 (wrong API key or expired token), CORS error (whitelist Retool's domain or proxy the request through a backend), timeout (API too slow or timeout setting too low), IP blocked (whitelist Retool's IP ranges in the API firewall), or wrong resource configuration (bad base URL, wrong auth type). Each has a specific fix.

Quick facts about this guide
FactValue
ToolRetool
DifficultyIntermediate
Time required20-30 min
CompatibilityRetool Cloud and Self-hosted
Last updatedMarch 2026

A Systematic Approach to Retool API Troubleshooting

When a Retool app silently shows no data or displays an error state, the cause is almost always one of six issues: authentication failure, CORS policy, request timeout, firewall/IP block, incorrect resource configuration, or malformed query parameters.

Retool's Debug Panel is the primary tool for diagnosis — it shows the exact HTTP status code, error message, and response body for every query execution. This information tells you which category the problem falls into and points directly to the fix.

This tutorial walks through each failure category with diagnostic steps and fixes. Start with the Debug Panel to identify the error, then jump to the relevant section.

Prerequisites

  • A Retool app with a REST API, GraphQL, or database resource query that is failing
  • Access to the Retool editor (Editor or Admin role)
  • Access to the API's documentation or admin panel to verify credentials and CORS settings

Step-by-step guide

1

Open the Debug Panel and identify the error

The first step for any API loading failure is to open the Debug Panel. Click the bug icon in the bottom bar of the Retool editor (or press Ctrl+D / Cmd+D). Click the Queries tab. Find your failing query in the list — it will have a red error indicator. Click the query name to expand it. Look at: (1) Status — the HTTP status code (401, 403, 404, 408, 500, 0/CORS), (2) Response body — the error message from the API, (3) Request — the URL and headers that were actually sent. These three fields tell you exactly what went wrong.

typescript
1// Common Debug Panel error patterns and their categories:
2
3// Status: 401 Unauthorized
4// → Authentication failure: wrong API key, expired token, missing header
5
6// Status: 403 Forbidden
7// → Authorization failure: correct credentials but insufficient permissions
8// → OR: IP address not whitelisted
9
10// Status: 0 + "CORS" in error message
11// → Browser blocked the request due to CORS policy
12// → Only appears when querying APIs directly from the browser (REST API resource)
13
14// Status: 408 or ETIMEDOUT
15// → Request timed out: API is slow or Retool timeout threshold too low
16
17// Status: 404 Not Found
18// → Wrong endpoint URL, wrong resource base URL, or path typo
19
20// Status: 500 Internal Server Error
21// → API-side error, not a Retool configuration issue

Expected result: Debug Panel shows the specific HTTP status and error message for the failing query.

2

Fix 401 Unauthorized: credential configuration errors

A 401 response means the API rejected the request because authentication is missing or invalid. Go to Resources (Settings → Resources or the Resources panel in the editor). Find the resource and click Edit. Check: (1) API key header — is the key still valid? Test it directly in Postman or curl to isolate whether the key itself works. (2) Auth type — is it set to 'Bearer Token', 'API Key', 'Basic Auth', or 'Header'? Verify it matches what the API documentation requires. (3) For OAuth resources, click 'Reconnect account' to refresh the token. Tokens expire and must be re-authorized.

typescript
1// Verify your credentials independently with curl:
2curl -X GET 'https://api.example.com/data' \
3 -H 'Authorization: Bearer YOUR_API_KEY'
4
5// If this returns 401, the key itself is wrong or expired
6// If this returns 200, the key works — check Retool resource configuration
7
8// Common Retool resource auth mistakes:
9// Mistake: Auth type = 'Bearer Token' but API expects 'Authorization: ApiKey ...'
10// Fix: Switch to 'Header' auth type, set header name 'Authorization', value 'ApiKey YOUR_KEY'
11
12// Mistake: API key stored as 'value' but resource sends it as URL parameter
13// Fix: Use 'URL parameter' auth type or add the key to the Base URL as ?apiKey=...

Expected result: After updating resource credentials, re-run the failing query. Debug Panel shows 200 OK response.

3

Fix CORS errors: browser-blocked API requests

CORS (Cross-Origin Resource Sharing) errors occur when a REST API resource makes requests directly from the browser to an API that doesn't include Retool's domain in its allowed origins. The Debug Panel shows status 0 or a network error mentioning 'CORS' or 'Access-Control-Allow-Origin'. Solutions: (1) Best: ask the API provider to add app.retool.com (for Retool Cloud) or your self-hosted domain to their CORS allowed origins. (2) If you control the API: add the Retool domain to your API's CORS configuration. (3) If neither is possible: create a Retool Workflow that proxies the request server-side, avoiding the browser CORS restriction entirely.

typescript
1// CORS error in Debug Panel:
2// 'Access to fetch at https://api.example.com blocked by CORS policy:
3// No Access-Control-Allow-Origin header is present'
4
5// Option 1: If you control the API backend, add CORS header:
6// Access-Control-Allow-Origin: https://app.retool.com
7// (or * for all origins — less secure)
8
9// Option 2: Proxy the request through a Retool Workflow
10// Workflows run server-side and are not subject to browser CORS restrictions
11
12// Option 3: Use Retool's built-in proxy
13// In the REST API resource, check 'Proxy requests through Retool' if available
14// This routes requests through Retool's servers, bypassing browser CORS
15
16// Option 4: Check if the API has a server-side SDK or Retool integration
17// Some APIs like Stripe have Retool-specific resources that handle CORS automatically

Expected result: After adding CORS headers or proxying the request, the CORS error disappears and the query returns data.

4

Fix 403 Forbidden and IP whitelisting issues

A 403 response can mean two different things: (1) Wrong permissions — the API key is valid but doesn't have access to the requested endpoint. Check the API's permission scopes and generate a new key with the required permissions. (2) IP whitelisting — the API's firewall only allows requests from specific IP addresses and Retool's IP is not on the list. This is common with corporate APIs, financial services APIs, and database APIs. For Retool Cloud, whitelist Retool's IP ranges in the API's firewall settings.

typescript
1// Retool Cloud outbound IP ranges (as of 2026):
2// Check current IPs at: docs.retool.com/docs/ip-allowlist
3// Retool Cloud uses AWS infrastructure — IPs are region-specific
4
5// For self-hosted Retool, the outbound IP is your server's public IP
6// Find it with: curl https://api.ipify.org on your Retool server
7
8// Diagnosing 403 vs IP block:
9// Test with Postman from a different IP (e.g., your local machine):
10// If Postman gets 200 but Retool gets 403 → IP whitelist issue
11// If both get 403 → permissions/scope issue with the API key itself
12
13// For database resources (Postgres, MySQL) behind a firewall:
14// Whitelist Retool's IP in your database firewall/security group
15// For AWS RDS: EC2 Security Groups → Inbound rules → add Retool IPs

Expected result: After whitelisting Retool's IP ranges, the 403 error resolves and queries return data.

5

Fix timeout errors: slow APIs and low timeout thresholds

Timeout errors occur when the API takes longer to respond than Retool's timeout threshold allows. Debug Panel shows status 408 or an 'ETIMEDOUT' error. Two possible causes: (1) The API is genuinely slow (complex query, large data set) — optimize the API query or paginate the results. (2) Retool's timeout threshold is too low for this API. In the resource settings, look for a 'Request timeout' or 'Timeout' field and increase it (default is often 10 seconds; try 30-60 seconds for slow endpoints). Also check if the API has a rate limit causing queuing delays.

typescript
1// Diagnose timeout vs API error:
2// Test the API directly with curl --max-time 60 to see actual response time:
3curl -w '\n\nTotal time: %{time_total}s' \
4 -X GET 'https://api.example.com/large-dataset' \
5 -H 'Authorization: Bearer YOUR_KEY'
6
7// If the API takes 15 seconds but Retool's timeout is 10s → increase timeout
8// If the API itself takes 60+ seconds → paginate the response
9
10// In Retool query settings, add pagination:
11// Use query parameters like ?page=1&limit=100 instead of fetching all records
12// Use table1.pageIndex and table1.pageSize for server-side pagination
13
14// For polling patterns that appear to 'not load':
15// Check if the query is set to 'Run on page load' → ensure this is enabled
16// Check 'Run query automatically when inputs change' for dynamic queries

Expected result: After increasing the timeout threshold or optimizing the API query, data loads successfully.

6

Verify resource configuration: base URL, auth type, and headers

If the Debug Panel shows a 404 or connection error, the resource itself may be misconfigured. Common issues: (1) Wrong base URL — trailing slash mismatch (https://api.example.com vs https://api.example.com/), or wrong version (v1 vs v2). (2) Missing required headers — some APIs require Content-Type or Accept headers on all requests. (3) Wrong environment — the resource might be pointing to a staging URL but you're testing against production data. Inspect the resource configuration by navigating to Resources, clicking Edit on your resource, and verifying every field.

typescript
1// Checklist for resource configuration:
2// [ ] Base URL: matches API documentation exactly (check for trailing slash)
3// [ ] Auth type: matches what the API expects (Bearer, API Key header, Basic, etc.)
4// [ ] Required headers: does the API require Content-Type: application/json?
5// [ ] API version: is the version in the base URL or as a header?
6
7// Common base URL mistakes:
8// Wrong: https://api.example.com/v1 (no trailing slash)
9// Wrong: https://api.example.com (missing /v1 version path)
10// Right: check exact format in API docs
11
12// Check query URL construction:
13// In the query editor, look at the URL field
14// The final URL = Base URL + URL path in query
15// Example: Base URL 'https://api.example.com/v1' + path '/users/{{ userId.value }}'
16// Final URL: https://api.example.com/v1/users/123
17
18// For GraphQL resources:
19// Base URL must be the exact GraphQL endpoint (not the API root)
20// Auth goes in the 'Headers' section, not a separate auth field in some cases

Expected result: Resource configuration verified and corrected. Queries use the correct URL and authentication.

7

Debug query-level issues: missing parameters and wrong data mapping

Sometimes the resource is configured correctly but the individual query has issues. Common query-level problems: (1) A required query parameter is missing or has a null value — check that all {{ component.value }} references in the query are resolving to actual values. (2) The query runs before the component that provides its input is loaded — enable 'Run query automatically when inputs change' instead of 'Run on page load'. (3) The query response data structure doesn't match what the app expects — check the response in the Debug Panel and verify the data path in your component bindings.

typescript
1// In the Debug Panel Queries tab, click your query to see:
2// 'Request' tab → URL and parameters that were actually sent
3// 'Response' tab → exact JSON returned by the API
4
5// Check for null parameters in the request:
6// If URL shows /users/undefined → userId.value is null when query runs
7// Fix: add 'Only run when {{ userId.value != null }}' condition to the query
8
9// Check data path binding:
10// API returns: { data: { users: [...] } }
11// Wrong component binding: {{ getUsersQuery.data }} → shows the whole object
12// Correct binding: {{ getUsersQuery.data.users }} → shows the array
13
14// For Transformer-processed data:
15// If query has a Transformer, the query's .data is the TRANSFORMED output
16// Debug: temporarily disable the Transformer to see the raw API response
17
18// Check 'Run on page load' setting:
19// If disabled, the query only runs when manually triggered or when inputs change
20// Enable it for queries that should load data when the app opens

Expected result: Query parameters resolve correctly, data path binding matches the API response structure, and data appears in components.

Complete working example

JS Query: diagnoseAPIFailure (troubleshooting helper)
1// JS Query: diagnoseAPIFailure
2// Run this query to get a diagnostic report for a failing API query
3// Replace 'yourQuery' with the name of your failing query
4
5const queryName = 'yourQuery'; // Replace with your query name
6const query = self; // This query is examining itself for demo purposes
7
8// In practice, run this after your failing query executes to inspect its state:
9console.log('=== API Failure Diagnostic Report ===');
10
11// 1. Check query execution status
12console.log('Query name:', queryName);
13console.log('Query data (result):', JSON.stringify(yourQuery.data, null, 2));
14console.log('Query error:', yourQuery.error);
15console.log('Is loading:', yourQuery.isFetching);
16
17// 2. Inspect environment context
18console.log('\n=== Environment ===');
19console.log('Retool environment:', retoolContext.environment);
20console.log('Current user:', current_user.email);
21
22// 3. Check all inputs to the failing query
23// (Replace with your actual input component names)
24console.log('\n=== Query Inputs ===');
25// console.log('userId:', userSelector.value);
26// console.log('dateFrom:', dateFrom.value);
27// console.log('dateTo:', dateTo.value);
28
29// 4. Detect common failure signatures from error message
30const errorStr = JSON.stringify(yourQuery.error || '');
31let diagnosis = 'Unknown error';
32
33if (errorStr.includes('401') || errorStr.toLowerCase().includes('unauthorized')) {
34 diagnosis = '401 Unauthorized — check API key/token in resource settings';
35} else if (errorStr.includes('403') || errorStr.toLowerCase().includes('forbidden')) {
36 diagnosis = '403 Forbidden — check permissions scope or IP whitelist';
37} else if (errorStr.toLowerCase().includes('cors') || errorStr.toLowerCase().includes('access-control')) {
38 diagnosis = 'CORS error — API must allow Retool domain or use proxy';
39} else if (errorStr.includes('timeout') || errorStr.includes('ETIMEDOUT')) {
40 diagnosis = 'Timeout — increase resource timeout or paginate the API response';
41} else if (errorStr.includes('404')) {
42 diagnosis = '404 Not Found — check base URL and endpoint path in resource/query';
43} else if (errorStr.includes('500')) {
44 diagnosis = '500 Server Error — API-side issue, not a Retool config problem';
45} else if (!yourQuery.data && !yourQuery.error) {
46 diagnosis = 'No data and no error — query may not be running (check Run on page load)';
47}
48
49console.log('\n=== Diagnosis ===');
50console.log('Likely cause:', diagnosis);
51console.log('\nFull error object:', JSON.stringify(yourQuery.error, null, 2));
52
53// 5. Display result in notification for quick viewing
54utils.showNotification({
55 title: 'Diagnostic result',
56 description: diagnosis,
57 notificationType: 'info',
58 duration: 8,
59});

Common mistakes

Why it's a problem: Assuming the app's empty state means the query ran and returned no results, when it actually means the query hasn't run at all

How to avoid: Check the Debug Panel Queries tab — if the query doesn't appear in the list, it hasn't executed. Verify 'Run on page load' is enabled or that the component/trigger that should fire it is actually triggering it.

Why it's a problem: Updating API credentials in the app's query instead of in the resource configuration, causing the key to appear in query code and break when it expires

How to avoid: API keys and tokens belong in Resources (Settings → Resources → Edit). Queries should reference the resource, not hardcode credentials. This also enables credential reuse across multiple queries.

Why it's a problem: Confusing Retool Cloud's IP ranges with the self-hosted Retool server's IP when setting up API whitelists

How to avoid: For Retool Cloud, use the IP ranges from docs.retool.com/docs/ip-allowlist. For self-hosted Retool, the outbound IP is your server's public IP — run curl https://api.ipify.org on the server to find it. They are different IPs.

Why it's a problem: Debugging CORS errors by adding !important CSS or changing query parameters — CORS is a browser security policy, not a Retool configuration issue

How to avoid: CORS errors require one of three fixes: (1) the API adds the Retool domain to its CORS allowed origins, (2) requests are proxied server-side via a Retool Workflow, or (3) you switch from a REST API resource to a backend resource (Postgres, GraphQL) that doesn't go through the browser.

Best practices

  • Always check the Debug Panel Queries tab first when API data doesn't load — it shows the exact HTTP status and error, eliminating guesswork
  • Test API credentials independently in Postman or curl before debugging Retool — this isolates whether the issue is Retool configuration or the API itself
  • Add 'Only run when' conditions to queries that depend on user input: {{ inputComponent.value != null && inputComponent.value !== '' }} prevents queries from firing with undefined parameters
  • Use Retool's resource 'Test connection' button after any credential change to verify the fix before refreshing the app
  • For APIs behind corporate firewalls, keep a documented list of Retool's IP ranges and include them in firewall review processes when IPs change
  • Set query-specific timeout values for known-slow endpoints rather than increasing the global resource timeout, which affects all queries on that resource

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

My Retool app has a REST API resource query that isn't loading data. The Debug Panel shows a 403 Forbidden error. The API is an internal company API behind a firewall. Walk me through: (1) how to determine if this is an IP whitelist issue vs a permissions/scope issue, (2) where to find Retool Cloud's outbound IP ranges to whitelist, (3) how to test whether the API key has the right permissions using curl, (4) the difference between 401 and 403 in terms of what they tell me about the failure. Also explain what to check if the Debug Panel shows no error but the query also returns no data.

Retool Prompt

Debug Retool API not loading: Open Debug Panel (bottom bar) → Queries tab → click failing query. Check Status code: 401=bad credentials (fix in Resources → Edit), 403=IP block (whitelist Retool IP at docs.retool.com/docs/ip-allowlist), 0/CORS=browser blocked (proxy via Workflow), timeout=increase Resource timeout setting. Check query inputs: {{ componentName.value }} must not be null. Verify 'Run on page load' is enabled. Test API directly with curl to isolate Retool vs API issue.

Frequently asked questions

The Debug Panel shows no error, but my table is empty — what does that mean?

If the query ran successfully (green indicator, 200 status) but the table shows no data, the issue is in the data binding, not the API call. Check three things: (1) the data path — does your table's Data Source say {{ query1.data }} when it should be {{ query1.data.items }} or {{ query1.data.results }}? (2) Is a Transformer filtering out all results? (3) Is there a filter or 'Only run when' condition that's causing the query to return 0 rows? Open the Debug Panel, click the query, and inspect the raw Response to see what the API actually returned.

My API works fine in Postman but returns a CORS error in Retool — why?

Postman makes requests from your local machine (a native app, not a browser), so it bypasses browser CORS restrictions. Retool's REST API resource makes requests from your browser, which enforces CORS. The API needs to include an Access-Control-Allow-Origin header that permits the Retool domain. If you can't modify the API, proxy the request through a Retool Workflow — Workflows run server-side and are not subject to browser CORS restrictions.

I whitelisted Retool's IPs but still get 403 — what else should I check?

If IP whitelisting is already in place but 403 persists, check API key scope/permissions: some APIs issue keys with different permission tiers. Generate a new key with admin or full-access permissions and test. Also check if the API requires a specific HTTP method (GET vs POST) for the endpoint — a 403 on a GET to an endpoint that expects POST can look like an access error. Finally, verify there's no additional auth layer like an API gateway in front of the backend API.

How do I make a query retry automatically after a 401 error?

Retool doesn't have built-in automatic retry with token refresh, but you can implement it in a JS Query. After triggering the failing query, check if the error is a 401, then trigger a 'refreshToken' query to get a new token, update the resource credential via the Retool API, and re-trigger the original query. For OAuth resources, Retool handles token refresh automatically if the resource is configured with a refresh token — the 401 handling is built in.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Learning is great. Shipping is faster with help.

Our engineers have built 600+ apps on Retool and the tools around it. If your project needs to be live sooner than your learning curve allows — book a free consultation.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.