Key Takeaway
Adalo custom actions let your app call any external REST API: you define the endpoint, method, headers (including an auth token), and request body, then map the response fields back into your app. The setup is straightforward for a single GET or POST. The hard parts are auth that has to refresh, CORS in the web player, rate limits, and chaining several calls together, which is where a no-code app slowly turns into a part-time integration job.
Adalo can talk to almost any external service through its Custom Action feature. If a platform has a REST API, you can usually wire it into an Adalo screen: send data out, pull data in, trigger an automation, charge a card, post to a CRM. This guide walks through the real setup step by step, with accurate detail on headers, auth tokens, request bodies, and reading the response, and then the pitfalls that actually trip people up (CORS and rate limits chief among them). It is written to be useful first. The honest build-vs-buy note is at the very end.
Adalo integrations: the three ways to connect
Before custom actions specifically, it helps to know your options. Adalo connects to the outside world in roughly three ways, and picking the right one saves a lot of rework.
| Method | What it is | Best for |
|---|---|---|
| Marketplace integrations | Pre-built blocks (Stripe, Google Maps, etc.) | Common services with an official component |
| External Collections | An external API mapped as a data source you can list and bind | Reading lists of records from an API into list components |
| Custom Actions | A single REST call fired on a button or screen action | Sending data out or triggering something on a button tap |
This guide focuses on Custom Actions, because that is the most flexible path and the one people search for. External Collections are worth knowing about when your goal is to display a feed of records rather than fire a one-off call.
How to set up a custom action in Adalo
A custom action is a single configured REST request. You build it once, then attach it to any action (a button tap, a form submit, an on-screen-load trigger). Here is the accurate sequence as of 2026.
Step 1: Create the custom action
- Open your app, then go to the left sidebar and find the bottom icon for the marketplace or the gear, then choose Custom Actions (in current Adalo it lives under the third tab in the left rail, the one with the puzzle or settings glyph).
- Click New Custom Action and give it a clear name like "Create CRM Contact" or "Send Welcome Email." The name is what you will see later when attaching it to a button.
Step 2: Set the method and endpoint URL
- Pick the HTTP method. GET retrieves data, POST creates, PUT or PATCH updates, DELETE removes.
- Paste the full endpoint URL from the API's documentation, for example
https://api.example.com/v1/contacts. Get this exactly right, includinghttpsand the version path.
Step 3: Add headers, including your auth token
Headers are how most APIs authenticate the request. The two you will use most:
- Content-Type set to
application/jsonfor almost all JSON APIs. Without it, many servers ignore your body. - Authorization set to your token. The common format is
Bearer YOUR_API_KEY. Some APIs use a custom header likex-api-keyinstead, so check the docs. Type the wordBearer, a space, then the key.
A practical safety note: an API key placed in an Adalo custom action is shipped to the client app, so treat it as exposed. Use a key scoped to the narrowest permissions the service allows, never a master or admin key, and rotate it if you suspect it leaked. For anything sensitive, route the call through a middle layer (more on that under pitfalls).
Step 4: Define the request body and magic-text inputs
For POST, PUT, and PATCH, you build the JSON body Adalo will send. This is where Adalo's magic text matters. You write the JSON keys the API expects, and for the values you insert dynamic inputs that the action will ask for at runtime.
A typical body for creating a contact looks like this:
{ "email": "[Email]", "first_name": "[First Name]", "source": "mobile app" }
Each bracketed value becomes an input on the custom action. When you later attach this action to a button, Adalo prompts you to bind each input to real data, for example the logged-in user's email or a form field. Match the JSON keys to the API's documented field names precisely, since APIs are case-sensitive and will silently drop fields they do not recognize.
Step 5: Map the response (the easy part to skip, and the one that breaks bindings)
Adalo asks you to provide a sample response so it can learn the shape of the data coming back. Paste a real example response from the API docs or from a test call. Adalo parses it and lets you map fields, for example pulling the returned record's id so you can save it, or reading a status field to branch your screen logic.
- If the API returns the object nested (for example under a
datakey), map to the nested path, not the top level. - If you skip this, the action still fires but you get nothing usable back, which is fine for fire-and-forget calls and a problem when you need the returned ID.
Step 6: Test, then attach to a button
- Use Adalo's Test button inside the custom action editor. It sends a live request. Read the raw response. A 200 or 201 status means success; a 4xx means your request was wrong; a 5xx means the server failed.
- Once it tests clean, go to any button or form, add an action, choose your custom action, and bind each input to live data.
Reading responses and handling errors
The status code tells you what happened. Knowing the common ones saves hours of guessing.
| Code | Meaning | Usual fix |
|---|---|---|
| 200 / 201 | Success | Nothing, you are good |
| 400 | Bad request | Body JSON malformed or a field is the wrong type |
| 401 / 403 | Auth failed or forbidden | Check the token, the Bearer prefix, and key permissions |
| 404 | Wrong URL | Fix the endpoint path or the record ID in it |
| 429 | Rate limited | Slow down calls, see rate limits below |
| 500 / 502 / 503 | Server error | Not your fault, retry or contact the API provider |
Inside Adalo, you can branch on the response. A common pattern: after the custom action runs, use conditional visibility or a second action that only fires if the mapped status field equals what you expect. Adalo's error handling is shallow compared to real code, so the practical move is to keep each action small and predictable.
Common pitfalls (the part that costs you a weekend)
CORS errors in the web player
This is the single most common surprise. When you preview or publish your Adalo app as a web app, the API call runs from the browser, and the browser enforces CORS (Cross-Origin Resource Sharing). If the target API does not return the right Access-Control-Allow-Origin header, the browser blocks the response and you see a CORS error in the console even though the same call works fine on a native iOS or Android build.
Things to know:
- Native mobile builds generally do not hit CORS. The problem is specific to the web player.
- You cannot fix CORS from Adalo. It is the API server's responsibility to send the allow header.
- The reliable workaround is a proxy or middle layer. Route the call through Make (formerly Integromat), Zapier webhooks, or a small serverless function (a Cloudflare Worker or AWS Lambda) that adds the CORS headers and forwards the request. Your Adalo custom action then points at your proxy URL, not the original API.
Rate limits and the 429
Most APIs cap how many requests you can make per second or per minute. If an Adalo list triggers a call per row, or a button fires repeatedly, you can blow past the limit and start getting 429 responses. Mitigations:
- Do not put a custom action inside a list that renders many rows at once.
- Debounce buttons by disabling them after the first tap (toggle a true/false field on tap).
- If you need bulk syncing, batch it through an external automation tool on a schedule rather than firing live from the app.
Auth tokens that expire
Static API keys are easy. OAuth tokens that expire are not. Adalo has no native way to run a refresh-token flow before each call. If your API issues short-lived access tokens, you will need a middle layer (Make, a serverless function) that handles the refresh and exposes a stable endpoint to Adalo. This is the most common reason a "quick integration" turns into an ongoing maintenance task.
Magic text and JSON quoting
When you insert a magic-text value into the body, make sure string values stay inside quotes and number or boolean values do not. A common 400 error is sending "age": "[Age]" when the API wants a number, or breaking the JSON because a user's input contained a quote character. Validate inputs before they reach the body where you can.
Nested responses and arrays
If the API returns an array or deeply nested object, Adalo's field mapper can struggle. Map to the exact path, and if the structure is complex, flatten it in a middle layer so Adalo receives a simple, predictable object.
A realistic example: posting a signup to your CRM
Say you want every new app user pushed into a CRM. The flow:
- Create a custom action named "Create CRM Contact," method POST, URL set to the CRM's contacts endpoint.
- Headers:
Content-Type: application/jsonandAuthorization: Bearer YOUR_KEY(a scoped key, not admin). - Body:
{ "email": "[Email]", "name": "[Name]", "tag": "app-signup" }. - Paste a sample response, map the returned contact
id. - On your signup form's submit button, add the action after the "sign up" action, and bind Email and Name to the new user's fields. Save the returned id to the user record so you can update the contact later.
That works cleanly for one call. The friction shows up when you then want to also send a welcome email, update a second system, and refresh an expiring token. Each addition is another action, another mapping, another thing that can break on a Tuesday.
FAQ
Can Adalo connect to any external API?
Almost any REST API that accepts JSON over HTTPS and uses header-based or query-based auth. Custom actions cover one-off calls, and external collections cover reading lists of records. APIs that require OAuth refresh flows, SOAP, or unusual auth typically need a middle layer (Make, Zapier, or a serverless function) between Adalo and the API.
Why does my Adalo API call work on mobile but fail on web with a CORS error?
Because native builds do not enforce CORS but the browser-based web player does. If the API does not return an Access-Control-Allow-Origin header, the browser blocks the response. You cannot fix this inside Adalo. Route the call through a proxy (a serverless function or an automation tool) that adds the CORS headers and forwards the request.
Where do I put the API key in an Adalo custom action?
In the headers, usually as an Authorization header with the value Bearer YOUR_KEY, or in a custom header like x-api-key if the API requires it. Use a key with the narrowest permissions possible, since the key ships to the client and should be treated as exposed.
How do I handle rate limits (429 errors) in Adalo?
Avoid firing custom actions inside large lists, disable buttons after the first tap to prevent rapid repeats, and move bulk or scheduled syncing to an external automation tool instead of live calls from the app. A 429 means you exceeded the API's allowed requests per second or minute, so the fix is spacing the calls out.
How do I refresh an expiring OAuth token in Adalo?
Adalo cannot run a refresh-token flow on its own. The standard solution is a middle layer (a serverless function or a tool like Make) that holds the refresh token, gets a fresh access token, calls the API, and returns the result to Adalo through a stable endpoint. Adalo's custom action then points at that endpoint instead of the original API.
The bottom line
Adalo custom actions are genuinely capable. For a single clean call, a contact created, an email triggered, a record fetched, the setup above gets you there in an afternoon, and you should build it yourself. Where it stops being fun is when the integration grows a tail: CORS proxies, token refreshers, rate-limit debouncing, response-flattening, and three chained calls that all have to succeed in order. At that point the "no-code" app has quietly become a part-time software job, and the person doing it is usually a founder or an ops lead who has another role to do.
That is the honest fork. If your integrations are simple and stable, keep them in Adalo. If they have turned into ongoing maintenance, there is a done-for-you alternative. Rehost is a small Los Angeles team that designs, builds, hosts, monitors, and operates custom apps and websites, including all of the API glue, so you never log into a dashboard. You send a plain message like "connect the new payment provider" and we ship the change. You own the app, the App Store and Google Play developer accounts, the domain, the code repository, and your customer data, all portable if you ever leave. Business pricing starts at $950/mo billed by monthly active users, with no setup fee, month to month. A custom website typically launches in under a week and a full app build in about two weeks. You can see how it works on what is Rehost, check the math on the app calculator, or read the business plan and pricing. When the integration work has become its own job, that is the moment to tell us what you are building and we will tell you honestly whether building it yourself or handing it off makes more sense.