Connect Retool to Facebook Ads using a REST API Resource pointing to the Meta Marketing API (graph.facebook.com). Authenticate with a System User access token from Meta Business Manager — a long-lived token that does not expire after 60 days like standard user tokens. Query campaign performance, ad set metrics, and creative insights, then display them in Retool Charts and Tables for a media buying operations dashboard your paid social team can use daily.
| Fact | Value |
|---|---|
| Tool | Facebook Ads |
| Category | Marketing |
| Method | REST API Resource |
| Difficulty | Intermediate |
| Time required | 30 minutes |
| Last updated | April 2026 |
Why connect Retool to Facebook Ads?
Meta Ads Manager provides comprehensive campaign data, but its reporting interface has significant limitations for performance marketing teams: it cannot be customized to match internal KPI definitions, it cannot be combined with CRM or revenue data from other systems, and building automated alerts or bulk-editing campaigns requires using Meta's native tools one at a time. Retool gives media buyers and paid social managers a custom operations hub backed directly by the Meta Marketing API.
The most impactful use case is a unified ad performance dashboard that combines Meta campaign data with actual revenue data from a PostgreSQL database or Stripe. Rather than trusting Meta's conversion tracking alone, teams can compare Meta-reported conversions against actual database purchases for the same time period, calculate true ROAS, and identify discrepancies. Retool's server-side query proxy handles the Meta API authentication securely, making it practical to build shared dashboards that multiple team members can view without each needing to authenticate with Meta.
Meta's Marketing API uses the Meta Graph API framework. All resources (accounts, campaigns, ad sets, ads) are identified by numeric IDs accessed at /v{version}/{id}. Performance data comes from the Insights API endpoint attached to any object level: /act_{account_id}/insights returns account-level metrics, /{campaign_id}/insights returns campaign-level metrics. Understanding this hierarchical structure — Account → Campaign → Ad Set → Ad — is key to building efficient queries that retrieve the right granularity of data.
Integration method
Facebook Ads connects via Retool's REST API Resource targeting the Meta Marketing API at https://graph.facebook.com. Authentication uses a System User access token from Meta Business Manager — a server-to-server credential that never expires (unlike standard OAuth user tokens) and is purpose-built for API integrations. All API requests proxy through Retool's server-side infrastructure, keeping your access token off the client and eliminating any CORS concerns. You query the Insights API for performance metrics and the Campaigns/Ad Sets/Ads APIs for structure and targeting data.
Prerequisites
- A Meta Business Manager account (business.facebook.com) with an active ad account
- Admin access to Meta Business Manager to create System Users and assign ad account permissions
- The numeric ad account ID (visible in Ads Manager URL as act_XXXXXXXXXX or in Business Settings)
- Access to the Meta Developers portal (developers.facebook.com) to create an app if needed for advanced API access
- A Retool account with Resource creation permissions
Step-by-step guide
Create a Meta System User and generate an access token
Standard Meta OAuth user tokens expire after 60 days and require re-authentication through a browser flow — impractical for a Retool server-side integration. System Users are service accounts in Meta Business Manager designed specifically for API integrations; their tokens do not expire unless manually revoked. In Meta Business Manager (business.facebook.com), go to Business Settings (gear icon). In the left sidebar, navigate to Users → System Users. Click Add to create a new System User. Give it a descriptive name (e.g., Retool API Integration) and set the role to Admin (for full read/write access) or Employee (for read-only access to most data). Click Create System User. The new user appears in the list. Click Generate New Token on the System User. Select your app from the dropdown (create a basic app in Meta Developers portal if you do not have one — a Business type app works). In the permissions section, enable ads_read for read-only reporting access, plus ads_management if you need to pause campaigns or adjust budgets from Retool. Click Generate Token. Meta displays the token — copy it immediately. Unlike standard tokens, System User tokens do not have a 60-day expiry unless you set one explicitly. After generating the token, assign the System User to your ad account: in Business Settings → Accounts → Ad Accounts, select your ad account, click Add People, and add the System User with Analyst access (read-only) or Advertiser access (read/write).
Pro tip: When generating the System User token, select Never expire for the token expiry option if shown — this creates a permanent token suitable for production integrations. If your app requires token rotation for compliance, set a longer expiry (e.g., 90 days) and schedule a reminder to rotate it.
Expected result: You have a Meta System User access token (a long alphanumeric string) and the System User is assigned to your ad account with the appropriate permission level.
Configure the Meta Marketing API Resource in Retool
In Retool, navigate to the Resources tab and click Add Resource. Select REST API from the resource type list. Name the resource Meta Marketing API or Facebook Ads. In the Base URL field, enter https://graph.facebook.com/v19.0 — use a recent stable API version (Meta updates version numbers regularly; v19.0 was current as of early 2024, check the Meta developer changelog for the latest stable version). In the Headers section, add a default header that will be sent with every request: click Add Header, set the name to Authorization and the value to Bearer {{ config.META_ACCESS_TOKEN }}. This references a Retool configuration variable for the access token. Alternatively, you can add the token as a URL parameter named access_token — Meta's Graph API accepts authentication via either the Authorization header or an access_token URL parameter. To store the token as a configuration variable: go to Settings → Configuration Variables in Retool, click Add variable, name it META_ACCESS_TOKEN, paste the System User token as the value, and mark it as secret. Using a configuration variable rather than hardcoding the token in the resource allows credential rotation without editing the resource, and the secret flag prevents the token from being exposed in frontend context. Click Save on the Resource and test it by creating a quick GET query to /me/adaccounts to confirm the token has access to your ad accounts.
Pro tip: Always include the API version in the base URL (e.g., /v19.0). Using an unversioned URL means Meta will use the latest version, which can break queries when Meta releases breaking changes. Pinning to a version gives you control over when to upgrade.
Expected result: The Meta Marketing API Resource is saved in Retool with the base URL and Bearer token authentication. A test query to /me/adaccounts returns a list of ad accounts accessible to your System User.
Query campaign-level Insights for performance data
Create a new query targeting your Meta Marketing API resource. Set Method to GET. Set Path to /act_{{ retoolContext.configVars.META_AD_ACCOUNT_ID }}/insights — replace the ad account ID reference with your actual account ID in the format act_123456789 (the act_ prefix is required). In the URL Parameters section, add the following parameters to control what data the Insights API returns. Add fields with a comma-separated list of metrics: campaign_id, campaign_name, spend, impressions, clicks, ctr, cpm, cpc, reach, frequency, and actions (for conversions). The actions field returns all conversion events as an array. Add date_preset with value last_30d for the last 30 days, or use time_range with a JSON value like { since: {{ dateRangePicker.value[0] }}, until: {{ dateRangePicker.value[1] }} } for custom date ranges. Add level with value campaign to get campaign-level aggregation (options: account, campaign, adset, ad). Add limit with value 200 to retrieve up to 200 campaigns. Run the query. Meta returns a data array with one object per campaign containing the requested metrics. Note that the actions field returns an array of objects like [{ action_type: 'purchase', value: '15' }] — you need to extract the specific action types in your transformer.
1// JavaScript transformer for Meta Insights API response2// Flatten the response and extract specific conversion action types3const campaigns = data.data || [];45return campaigns.map(campaign => {6 // Extract specific action types from the actions array7 const actions = campaign.actions || [];8 const getAction = (type) => {9 const action = actions.find(a => a.action_type === type);10 return action ? parseFloat(action.value) : 0;11 };1213 const purchases = getAction('purchase');14 const addToCart = getAction('add_to_cart');15 const leads = getAction('lead');16 const spend = parseFloat(campaign.spend || 0);1718 return {19 campaign_id: campaign.campaign_id || '',20 campaign_name: campaign.campaign_name || '',21 spend: spend.toFixed(2),22 spend_display: `$${spend.toFixed(2)}`,23 impressions: parseInt(campaign.impressions || 0),24 clicks: parseInt(campaign.clicks || 0),25 ctr: campaign.ctr ? (parseFloat(campaign.ctr) * 100).toFixed(2) + '%' : '0%',26 cpm: campaign.cpm ? `$${parseFloat(campaign.cpm).toFixed(2)}` : '$0',27 cpc: campaign.cpc ? `$${parseFloat(campaign.cpc).toFixed(2)}` : '$0',28 reach: parseInt(campaign.reach || 0),29 purchases: purchases,30 add_to_cart: addToCart,31 leads: leads,32 cost_per_purchase: purchases > 0 ? `$${(spend / purchases).toFixed(2)}` : 'N/A',33 roas: purchases > 0 && spend > 0 ? (purchases / spend * 100).toFixed(2) : '0'34 };35});Pro tip: The actions array in Meta's Insights response uses action_type strings like 'purchase', 'add_to_cart', 'lead', 'offsite_conversion.fb_pixel_purchase' — the exact type depends on how your pixel events and conversions are named. Check your Ads Manager Events Manager to find the exact action_type strings your account uses.
Expected result: The Insights query returns a flat array of campaign objects with spend, impressions, clicks, CTR, and extracted conversion counts. The data is ready to bind to a Table component.
Build the ads performance dashboard with Charts
With the Insights data available, build the dashboard layout. Drag a Table component onto the canvas and bind it to {{ getInsights.data }}. Configure columns with appropriate formatting: spend with currency format, ctr and roas as numbers, purchases as integer. Enable sort on all metric columns so buyers can rank campaigns by any KPI. Add conditional formatting: highlight rows where cost_per_purchase is above a target value (reference a Number input labeled Target CPP to make this dynamic). Add a DateRangePicker component at the top of the dashboard. Create a second Insights query for daily data to power trend charts — use the same endpoint but add time_increment: 1 to the URL parameters and add date as a field. This returns one row per day. Drag a Chart component below the table and bind it to {{ getDailyInsights.data }}. Set Chart type to Line, X axis to date, and add two data series: spend and purchases. This creates a dual-axis view showing spend trend alongside conversion volume. Add a second Chart as a bar chart showing the same campaigns table data sorted by spend — this gives a visual performance ranking. Add Stat components at the top showing totals for the period: total spend, total purchases, and blended ROAS — calculate these with a JavaScript query that sums the campaigns data array.
1// JavaScript query to compute period totals for Stat components2// Reference this query in Stat component value fields3const campaigns = getInsights.data || [];45const totalSpend = campaigns.reduce((sum, c) => sum + parseFloat(c.spend || 0), 0);6const totalPurchases = campaigns.reduce((sum, c) => sum + (parseInt(c.purchases) || 0), 0);7const totalImpressions = campaigns.reduce((sum, c) => sum + (parseInt(c.impressions) || 0), 0);8const totalClicks = campaigns.reduce((sum, c) => sum + (parseInt(c.clicks) || 0), 0);9const blendedRoas = totalSpend > 0 ? (totalPurchases / totalSpend * 100).toFixed(2) : 0;1011return {12 total_spend: `$${totalSpend.toFixed(2)}`,13 total_purchases: totalPurchases,14 blended_roas: blendedRoas + 'x',15 total_impressions: totalImpressions.toLocaleString(),16 blended_ctr: totalImpressions > 017 ? ((totalClicks / totalImpressions) * 100).toFixed(2) + '%'18 : '0%'19};Pro tip: Meta's Insights API has its own rate limits: 200 calls per hour per ad account. For dashboards with multiple queries (account level, campaign level, daily breakdown), cache each query for at least 5-15 minutes to stay within limits.
Expected result: A complete Facebook Ads dashboard displays: period total Stats at the top, a campaigns performance Table in the middle, and a spend/conversions trend Chart at the bottom — all updating when the date range picker changes.
Add campaign management and budget controls
Beyond reporting, Retool can control Facebook Ads campaigns if the System User has Advertiser permission. Create a query to pause or activate campaigns: set Method to POST, Path to /{{ campaignsTable.selectedRow.campaign_id }}, and Body to { status: {{ statusToggle.value ? 'ACTIVE' : 'PAUSED' }} }. Wire this to a status toggle button on each campaign row. For budget adjustments, create a POST query to /{{ campaignsTable.selectedRow.campaign_id }} with Body { daily_budget: {{ Math.round(budgetInput.value * 100) }} } — Meta stores budgets in cents, so multiply by 100. Add a Confirm dialog before any status change or budget modification. These operations require ads_management permission in your System User token. Create a campaign lookup panel where buyers paste a campaign ID into a text input and see all ad sets and ads under that campaign using /{{ campaignIdInput.value }}/adsets and /{{ adsetIdInput.value }}/ads endpoints. The full campaign hierarchy becomes navigable from Retool. For teams building full paid media operations platforms combining Meta, Google, TikTok, and LinkedIn data with revenue attribution, RapidDev's team can architect a comprehensive multi-platform Retool solution.
1// Query to fetch ad sets for a selected campaign2// Path: /{{ campaignsTable.selectedRow.campaign_id }}/adsets3// Method: GET4// URL Parameters:5{6 "fields": "id,name,status,daily_budget,bid_amount,targeting,effective_status",7 "limit": "200"8}910// Transformer for ad sets response11const adsets = data.data || [];12return adsets.map(adset => ({13 id: adset.id || '',14 name: adset.name || '',15 status: adset.status || '',16 effective_status: adset.effective_status || '',17 daily_budget: adset.daily_budget18 ? `$${(parseInt(adset.daily_budget) / 100).toFixed(2)}`19 : 'Campaign Budget',20 bid_amount: adset.bid_amount21 ? `$${(parseInt(adset.bid_amount) / 100).toFixed(2)}`22 : 'Automatic'23}));Pro tip: When pausing or activating campaigns programmatically, be aware that Meta may enforce a cooldown period before recently paused ads can be reactivated. Include error handling in your query event handlers to surface these API error messages to the user.
Expected result: Campaign management controls work: toggling a campaign's status pauses or activates it in Meta Ads Manager, budget adjustments update correctly, and the campaign hierarchy (campaigns → ad sets → ads) is navigable from Retool.
Common use cases
Campaign performance dashboard for media buyers
Build a Retool dashboard that shows all active Facebook Ads campaigns with key performance metrics — spend, impressions, clicks, CTR, CPM, CPC, conversions, and ROAS — for the selected date range. A date range picker controls the reporting window. Charts show spend and conversion trends over time. The Table supports sorting by any metric column so buyers can quickly identify best and worst performing campaigns.
Build a Retool Facebook Ads dashboard that queries the Meta Insights API for all campaigns in an ad account with spend, impressions, clicks, ctr, cpm, cpc, and purchase conversions for a selected date range. Show a summary Table with all campaigns and a line Chart showing daily spend over time. Include a date range picker to adjust the reporting window.
Copy this prompt to try it in Retool
Ad set and audience performance comparison tool
Create a Retool panel that breaks down performance by ad set to help buyers understand which targeting audiences are most efficient. Query ad set level insights with demographic breakdowns (age, gender, placement) and display cost per result by audience segment. Buyers can identify which ad sets to scale, pause, or adjust targeting on, with direct links to Meta Ads Manager for implementation.
Build a Retool ad set comparison tool that queries Meta Marketing API ad set insights with spend, results, cost_per_result, frequency, and reach. Display a Table ranked by cost_per_result with a color coding rule that highlights ad sets above the target CPR threshold in red. Include a direct link to each ad set in Ads Manager.
Copy this prompt to try it in Retool
Cross-platform paid media ROI dashboard
Combine Facebook Ads spend and conversion data with Google Ads metrics and actual revenue from a PostgreSQL database in a single Retool dashboard. The dashboard runs three parallel queries — Meta Insights, Google Ads API, and a SQL query — and a JavaScript transformer joins the data by date. Stakeholders see total paid media spend versus actual revenue per day, removing the need to manually consolidate reports from multiple ad platforms.
Build a Retool cross-channel ROI dashboard that queries Facebook Ads spend and conversions, Google Ads spend and conversions, and a PostgreSQL 'revenue_by_day' table. Join the data by date in a JavaScript transformer and show total ad spend, total conversions, actual revenue, and calculated ROAS in a unified Table and a stacked bar Chart.
Copy this prompt to try it in Retool
Troubleshooting
API returns 190 error: 'Error validating access token: The session has been invalidated'
Cause: A standard user OAuth access token was used instead of a System User token and has expired (standard tokens expire after 60 days of inactivity).
Solution: Generate a System User token in Meta Business Manager rather than a personal user token. System User tokens do not expire by default. In Business Settings → System Users, click Generate New Token and ensure the Never option is selected for token expiry. Update the token in the Retool configuration variable.
Insights query returns an empty data array even for active campaigns
Cause: The ad account ID format is incorrect (missing the act_ prefix), the System User does not have access to the specified ad account, or the date range has no data.
Solution: Ensure the ad account ID in the API path includes the act_ prefix: /act_123456789/insights, not /123456789/insights. Verify the System User is assigned to the ad account in Business Settings → Accounts → Ad Accounts. Test with date_preset: last_30d to confirm data exists before using custom date ranges.
Rate limit error: 'User request limit reached' (error code 17 or 32)
Cause: The Insights API rate limit has been reached — 200 calls per hour per ad account, with more complex queries (many fields, long date ranges) consuming more of the rate limit budget.
Solution: Enable Retool query caching (5-15 minutes) on all Insights queries. Reduce the number of fields requested. Avoid re-running Insights queries on every user interaction — add a dedicated Refresh button and cache aggressively. For dashboards used by multiple people simultaneously, Meta's rate limits apply per ad account, not per user.
The 'purchases' action count is missing or always 0 in the transformer
Cause: The action_type string for purchases varies based on your pixel configuration — it may be 'offsite_conversion.fb_pixel_purchase' rather than 'purchase', or the conversion event uses a custom name.
Solution: Add a debug step to your transformer: return the raw actions array for one campaign to see all action_type values your account actually uses. Find your exact purchase action type and update the getAction() call in the transformer to match.
1// Debug transformer to see all action types2const firstCampaign = data.data?.[0];3return firstCampaign?.actions || [];4// Look at the action_type values in the output5// Common values: 'purchase', 'offsite_conversion.fb_pixel_purchase', 'lead', 'complete_registration'Best practices
- Use Meta System User tokens rather than personal user OAuth tokens — System User tokens do not expire, making them purpose-built for API integrations like Retool.
- Store the System User access token in a Retool configuration variable marked as secret — this prevents the token from being exposed to frontend JavaScript and enables rotation without editing the resource configuration.
- Always include the API version in the base URL (e.g., /v19.0) rather than using an unversioned URL — this protects against breaking changes when Meta releases new API versions.
- Request only the fields you need in the fields URL parameter — the Insights API response size is proportional to the fields requested, and unnecessary fields slow queries and consume more of the rate limit budget.
- Enable query caching (5-15 minutes) on Insights queries — ad performance data does not change by the second, and caching reduces Meta API calls significantly when multiple team members view the dashboard.
- Use time_increment: 1 in Insights queries for trend charts but use aggregated queries (no time_increment) for summary tables — this avoids fetching large daily datasets when only totals are needed.
- Add a date range picker that constrains selection to a maximum of 90 days — Meta's Insights API performance degrades significantly for longer date ranges and some metrics are only available for shorter windows.
- Pin campaign links in the Table to the corresponding Ads Manager URL (https://www.facebook.com/adsmanager/manage/campaigns?act={account_id}&selected_campaign_ids={campaign_id}) so buyers can navigate directly to Ads Manager from Retool.
Alternatives
Google Ads connects via REST API Resource using Google OAuth and the Google Ads API, and is better suited for search intent-based campaigns while Facebook Ads excels at interest and demographic targeting.
TikTok Ads connects via REST API Resource using the TikTok Marketing API and is a growing alternative for teams targeting younger demographics with video-first creative formats.
LinkedIn Ads connects via REST API Resource and is preferred for B2B campaigns targeting by job title, company, and industry, whereas Facebook Ads is stronger for B2C consumer targeting.
Frequently asked questions
What is the difference between a System User token and a regular OAuth user token for the Meta Marketing API?
A System User is a service account in Meta Business Manager that represents an automated system rather than a person. System User tokens do not expire (unless you set an expiry), are not tied to a personal Facebook profile, and can be assigned specific permissions on specific ad accounts. Standard OAuth user tokens expire after 60 days of inactivity and require re-authentication through a browser flow — making them impractical for server-side integrations like Retool.
Can Retool connect to Instagram ad accounts through the Meta Marketing API?
Yes. Instagram ad accounts are managed through Meta Business Manager and use the same Meta Marketing API. Campaigns, ad sets, and ads running on Instagram are accessible through the same /act_{account_id}/insights endpoint with the publisher_platform: instagram breakdown. You can filter Insights queries to show only Instagram placements using the breakdown and filtering parameters in the Insights API.
Can I pause or modify live campaigns from Retool?
Yes, if your System User token has ads_management permission (not just ads_read). Create POST queries targeting the campaign, ad set, or ad ID with status: PAUSED or ACTIVE, or update daily_budget. Always add confirmation dialogs before executing status changes — accidentally pausing active campaigns has immediate business impact. Consider restricting who in your team can access the management functions using Retool's app permissions.
How do I combine Facebook Ads data with revenue from my database in Retool?
Run both the Insights API query and your database query in parallel in Retool, then use a JavaScript query to join the datasets by date (using the date field from both sources as the join key). Both queries return arrays; a standard array reduce/map pattern builds a joined dataset. The channel ROI calculation pattern described in Step 4 demonstrates this approach. Retool JavaScript queries can reference any other query's .data property directly.
Does the Meta Marketing API have rate limits that could affect my Retool dashboard?
Yes. The Insights API limits to approximately 200 calls per hour per ad account, with complex queries (many fields, long date ranges, fine-grained breakdowns) consuming more of the limit. Enable Retool query caching (5-15 minutes) on all Insights queries and avoid running them automatically on every component interaction. For dashboards used by many team members, the per-ad-account rate limit applies across all users, so shared caching is important.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation