Skip to main content
RapidDev - Software Development Agency
replit-integrationsStandard API Integration

How to Integrate Replit with Facebook Ads

To integrate Replit with Facebook Ads, create a Meta developer app, complete the OAuth flow to obtain an access token with ads_management permissions, store it in Replit Secrets (lock icon πŸ”’), and call the Facebook Marketing API from Python or Node.js server-side code to manage campaigns, ad sets, and retrieve insights. Use Autoscale deployment for apps that trigger ad operations from a web interface.

What you'll learn

  • How to create a Meta developer app and obtain an ads_management access token
  • How to store Facebook access tokens securely in Replit Secrets
  • How to retrieve campaign performance insights using Python and Node.js
  • How to create and manage ad campaigns and ad sets via the Marketing API
  • How to handle token refresh and rate limiting for production Facebook Ads integrations
Book a free consultation
4.9Clutch rating ⭐
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read45 minutesMarketingMarch 2026RapidDev Engineering Team
TL;DR

To integrate Replit with Facebook Ads, create a Meta developer app, complete the OAuth flow to obtain an access token with ads_management permissions, store it in Replit Secrets (lock icon πŸ”’), and call the Facebook Marketing API from Python or Node.js server-side code to manage campaigns, ad sets, and retrieve insights. Use Autoscale deployment for apps that trigger ad operations from a web interface.

Why Connect Replit to Facebook Ads?

The Facebook Marketing API gives you programmatic control over every aspect of your Meta advertising campaigns β€” from creating campaigns and uploading creatives to pulling granular performance metrics across Facebook, Instagram, Messenger, and the Audience Network. Connecting your Replit app to the Marketing API enables automated campaign management, real-time reporting dashboards, bulk ad creation workflows, and custom budget optimization logic that goes beyond what Meta Ads Manager provides natively.

Common use cases include building internal dashboards that pull spend and conversion data from multiple ad accounts into a single view, creating automated rules that pause underperforming ad sets when cost-per-result exceeds a threshold, and syncing your own customer data to Meta Custom Audiences for retargeting. The Marketing API v18+ (also called Graph API) provides comprehensive coverage for all campaign management and reporting needs.

Replit's Secrets system (lock icon πŸ”’ in the sidebar) is essential for this integration because Meta access tokens are long-lived credentials that grant access to all ad accounts associated with your Meta Business account. Never embed access tokens in code or commit them to Git. Store them as FACEBOOK_ACCESS_TOKEN in Replit Secrets and rotate them regularly. Always call the Facebook Marketing API from your Replit server-side code β€” never from frontend JavaScript.

Integration method

Standard API Integration

You connect Replit to Facebook Ads by creating a Meta developer app, granting it ads_management and ads_read permissions, and completing an OAuth flow to obtain a long-lived page or system user access token. Store the token in Replit Secrets and call the Facebook Marketing API v18+ from your server-side Python or Node.js code. All API calls are authenticated by appending the access_token as a query parameter or passing it as a Bearer token in the Authorization header.

Prerequisites

  • A Replit account with a Python or Node.js project created
  • A Meta developer account at developers.facebook.com
  • A Meta Business account with at least one ad account that has active billing
  • Basic understanding of OAuth 2.0 and API authentication
  • Node.js 18+ or Python 3.10+ (both available on Replit by default)

Step-by-step guide

1

Create a Meta Developer App and Get API Access

Go to developers.facebook.com and click 'My Apps' > 'Create App'. Select 'Business' as the app type (this gives access to the Marketing API). Give the app a name and associate it with your Meta Business account. Click 'Create App'. Once the app is created, go to App Dashboard > Products and click 'Add Product'. Find 'Marketing API' and click 'Set Up'. This adds the Marketing API product to your app and gives you access to the API explorer. For development and testing, use the Meta Graph API Explorer at developers.facebook.com/tools/explorer to generate a short-lived user access token. Click 'Generate Access Token', select your app, and grant these permissions: ads_management, ads_read, business_management. Copy the token. For production use, you need a long-lived token or a System User access token. System User tokens do not expire and are the recommended approach for server-to-server integrations. Create a System User in Meta Business Manager under Business Settings > Users > System Users. Generate a token for the System User and assign it the required ad account permissions (Advertiser or Admin role). Store your Ad Account ID β€” it looks like 'act_123456789' (with the 'act_' prefix). You can find it in Meta Ads Manager in the URL or under Business Settings > Ad Accounts.

Pro tip: Use a System User token for production integrations β€” it never expires and does not require a personal Facebook login. Short-lived user tokens expire after 1-2 hours, and long-lived tokens expire after 60 days of inactivity.

Expected result: You have a Meta developer app, a valid access token with ads_management permissions, and your Ad Account ID (starting with 'act_') ready to store in Replit Secrets.

2

Store Facebook API Credentials in Replit Secrets

Open your Replit project and click the lock icon πŸ”’ in the left sidebar to open the Secrets pane. Add the following secrets: - Key: FACEBOOK_ACCESS_TOKEN β€” Value: your access token (user, long-lived, or system user) - Key: FACEBOOK_AD_ACCOUNT_ID β€” Value: your ad account ID in 'act_XXXXXXXXX' format - Key: FACEBOOK_APP_ID β€” Value: your Meta app ID (found in App Dashboard) - Key: FACEBOOK_APP_SECRET β€” Value: your Meta app secret (found in App Dashboard > Settings > Basic) Click 'Add Secret' after each one. The app secret is needed if you want to generate app-level access tokens or verify webhook signatures. In Python, access these with os.environ['FACEBOOK_ACCESS_TOKEN']. In Node.js, use process.env.FACEBOOK_ACCESS_TOKEN. Replit's Secret Scanner will flag API keys and tokens written directly into code files. If you paste a token into your source code accidentally, Replit will warn you and prompt you to move it to Secrets instead. Never include Facebook tokens in client-side JavaScript β€” they must only exist in your server-side environment.

Pro tip: Set a calendar reminder to rotate your Facebook access token before it expires (60 days for long-lived tokens). System User tokens do not expire but should still be rotated periodically as a security best practice.

Expected result: Four Secrets appear in the Replit Secrets pane: FACEBOOK_ACCESS_TOKEN, FACEBOOK_AD_ACCOUNT_ID, FACEBOOK_APP_ID, and FACEBOOK_APP_SECRET.

3

Retrieve Campaign Data and Insights with Python

The Facebook Marketing API is part of the Graph API. The base URL is https://graph.facebook.com/v18.0/. All requests include your access token, either as a query parameter (access_token=...) or in the Authorization: Bearer header. The official Python SDK (facebook-business) is available on PyPI and provides a convenient wrapper. Install the SDK in Replit by running pip install facebook-business in the Shell, or add it to requirements.txt. The SDK handles authentication, pagination, and response parsing automatically. Insights data (spend, impressions, clicks, conversions) is accessed via the /insights edge of any campaign, ad set, or ad object. Insights require specifying a date range and the fields you want. The API paginates large result sets β€” the SDK handles pagination automatically when you iterate over the result. Note that the Marketing API has a strict rate limiting system based on usage points. Each ad account gets a quota, and complex queries that touch many campaigns consume more points. If you hit rate limits (error code 17 or 32), implement exponential backoff in your retry logic.

facebook_ads_client.py
1import os
2import time
3from facebook_business.api import FacebookAdsApi
4from facebook_business.adobjects.adaccount import AdAccount
5from facebook_business.adobjects.campaign import Campaign
6from facebook_business.adobjects.adset import AdSet
7
8# Initialize the Facebook Ads API
9access_token = os.environ["FACEBOOK_ACCESS_TOKEN"]
10app_id = os.environ["FACEBOOK_APP_ID"]
11app_secret = os.environ["FACEBOOK_APP_SECRET"]
12ad_account_id = os.environ["FACEBOOK_AD_ACCOUNT_ID"] # e.g., 'act_123456789'
13
14FacebookAdsApi.init(app_id, app_secret, access_token)
15my_account = AdAccount(ad_account_id)
16
17def get_campaigns(status: list = None) -> list:
18 """
19 Fetch campaigns from the ad account.
20 status: list of statuses to filter, e.g., ['ACTIVE', 'PAUSED']
21 """
22 fields = [
23 Campaign.Field.id,
24 Campaign.Field.name,
25 Campaign.Field.status,
26 Campaign.Field.objective,
27 Campaign.Field.daily_budget,
28 Campaign.Field.lifetime_budget,
29 ]
30 params = {}
31 if status:
32 params['effective_status'] = status
33
34 campaigns = my_account.get_campaigns(fields=fields, params=params)
35 return [dict(c) for c in campaigns]
36
37def get_campaign_insights(campaign_id: str, date_preset: str = 'last_7d') -> dict:
38 """
39 Get performance insights for a campaign.
40 date_preset options: 'today', 'yesterday', 'last_7d', 'last_30d', 'this_month'
41 """
42 campaign = Campaign(campaign_id)
43 fields = ['spend', 'impressions', 'clicks', 'ctr', 'cpm', 'reach', 'actions']
44 params = {
45 'date_preset': date_preset,
46 'level': 'campaign'
47 }
48 insights = campaign.get_insights(fields=fields, params=params)
49 return dict(insights[0]) if insights else {}
50
51def get_all_campaign_insights(date_preset: str = 'last_7d') -> list:
52 """
53 Fetch insights for all active campaigns with rate limit handling.
54 """
55 campaigns = get_campaigns(status=['ACTIVE'])
56 results = []
57 for campaign in campaigns:
58 try:
59 insights = get_campaign_insights(campaign['id'], date_preset)
60 results.append({
61 'campaign_id': campaign['id'],
62 'campaign_name': campaign['name'],
63 'spend': insights.get('spend', '0'),
64 'impressions': insights.get('impressions', '0'),
65 'clicks': insights.get('clicks', '0'),
66 'ctr': insights.get('ctr', '0'),
67 })
68 time.sleep(0.1) # Respect rate limits
69 except Exception as e:
70 print(f"Error fetching insights for {campaign['name']}: {e}")
71 return results
72
73def pause_campaign(campaign_id: str) -> bool:
74 """Pause an active campaign."""
75 campaign = Campaign(campaign_id)
76 campaign.api_update(params={'status': Campaign.Status.paused})
77 print(f"Campaign {campaign_id} paused")
78 return True
79
80# Example usage
81if __name__ == "__main__":
82 print("Fetching active campaigns...")
83 campaigns = get_campaigns(status=['ACTIVE'])
84 print(f"Found {len(campaigns)} active campaigns")
85 for c in campaigns[:3]:
86 print(f" [{c['id']}] {c['name']} β€” {c['status']}")
87
88 print("\nFetching insights for last 7 days...")
89 insights = get_all_campaign_insights('last_7d')
90 for i in insights[:3]:
91 print(f" {i['campaign_name']}: ${i['spend']} spend, {i['clicks']} clicks")

Pro tip: The facebook-business SDK automatically handles cursor-based pagination β€” when you iterate over a result set with more than 25 items, it fetches subsequent pages automatically. You do not need to manually implement pagination for most use cases.

Expected result: Running the script prints active campaigns and their 7-day spend, impression, and click totals without API errors.

4

Build a Node.js Marketing API Integration

For Node.js projects, use the facebook-nodejs-business-sdk package (npm install facebook-nodejs-business-sdk) or make direct HTTP requests using axios. The SDK approach is recommended for complex operations like creating campaigns and ad sets, as it handles field validation and pagination automatically. The Express server below provides endpoints for fetching campaign insights and creating a new campaign. Campaign creation follows a hierarchy: Account > Campaign > Ad Set > Ad > Creative. You must create these in order β€” each child object requires its parent's ID. Note that creating real campaigns requires having a verified payment method on the ad account. For testing, use the account's /adcreativepreviews endpoint to preview creatives without spending money, and create campaigns with CAMPAIGN_STATUS = PAUSED so they do not go live during testing.

server.js
1const express = require('express');
2const { FacebookAdsApi, AdAccount, Campaign } = require('facebook-nodejs-business-sdk');
3
4const app = express();
5app.use(express.json());
6
7const ACCESS_TOKEN = process.env.FACEBOOK_ACCESS_TOKEN;
8const APP_ID = process.env.FACEBOOK_APP_ID;
9const APP_SECRET = process.env.FACEBOOK_APP_SECRET;
10const AD_ACCOUNT_ID = process.env.FACEBOOK_AD_ACCOUNT_ID; // 'act_XXXXXXXXX'
11
12// Initialize the API
13const api = FacebookAdsApi.init(ACCESS_TOKEN);
14const account = new AdAccount(AD_ACCOUNT_ID);
15
16// Get all campaigns with their status
17app.get('/campaigns', async (req, res) => {
18 try {
19 const campaigns = await account.getCampaigns(
20 ['id', 'name', 'status', 'objective', 'daily_budget'],
21 { effective_status: req.query.status ? [req.query.status] : ['ACTIVE', 'PAUSED'] }
22 );
23 res.json(campaigns.map(c => c._data));
24 } catch (err) {
25 console.error('Campaigns error:', err);
26 res.status(500).json({ error: err.message });
27 }
28});
29
30// Get insights for a specific campaign
31app.get('/campaigns/:id/insights', async (req, res) => {
32 try {
33 const campaign = new Campaign(req.params.id);
34 const insights = await campaign.getInsights(
35 ['spend', 'impressions', 'clicks', 'ctr', 'cpm', 'actions'],
36 { date_preset: req.query.period || 'last_7d', level: 'campaign' }
37 );
38 res.json(insights.length > 0 ? insights[0]._data : { message: 'No data for this period' });
39 } catch (err) {
40 res.status(500).json({ error: err.message });
41 }
42});
43
44// Get account-level spend summary
45app.get('/account/insights', async (req, res) => {
46 try {
47 const insights = await account.getInsights(
48 ['spend', 'impressions', 'clicks', 'reach'],
49 { date_preset: req.query.period || 'last_30d' }
50 );
51 res.json(insights.length > 0 ? insights[0]._data : { spend: '0' });
52 } catch (err) {
53 res.status(500).json({ error: err.message });
54 }
55});
56
57// Create a campaign (starts in PAUSED status for safety)
58app.post('/campaigns', async (req, res) => {
59 const { name, objective, daily_budget } = req.body;
60 if (!name || !objective) {
61 return res.status(400).json({ error: 'name and objective are required' });
62 }
63 try {
64 const campaign = await account.createCampaign(
65 [],
66 {
67 [Campaign.Fields.name]: name,
68 [Campaign.Fields.objective]: objective, // e.g., 'LINK_CLICKS', 'CONVERSIONS'
69 [Campaign.Fields.status]: Campaign.Status.paused,
70 [Campaign.Fields.special_ad_categories]: [],
71 ...(daily_budget ? { [Campaign.Fields.daily_budget]: daily_budget } : {})
72 }
73 );
74 res.status(201).json({ id: campaign.id, name });
75 } catch (err) {
76 console.error('Create campaign error:', err.response?.data);
77 res.status(500).json({ error: err.message });
78 }
79});
80
81// Pause or resume a campaign
82app.patch('/campaigns/:id/status', async (req, res) => {
83 const { status } = req.body; // 'ACTIVE' or 'PAUSED'
84 if (!['ACTIVE', 'PAUSED'].includes(status)) {
85 return res.status(400).json({ error: 'status must be ACTIVE or PAUSED' });
86 }
87 try {
88 const campaign = new Campaign(req.params.id);
89 await campaign.update([Campaign.Fields.status], { [Campaign.Fields.status]: status });
90 res.json({ success: true, id: req.params.id, status });
91 } catch (err) {
92 res.status(500).json({ error: err.message });
93 }
94});
95
96app.listen(3000, '0.0.0.0', () => {
97 console.log('Facebook Ads integration server running on port 3000');
98});

Pro tip: Always create new campaigns with status: 'PAUSED' during development. This prevents accidental ad spend while testing your integration. Only set status to 'ACTIVE' from production code with explicit user confirmation.

Expected result: The server starts on port 3000. A GET request to /campaigns returns a JSON array of your ad account's campaigns with their current status and budget.

5

Handle Rate Limits and Deploy

The Facebook Marketing API enforces rate limits at the account level using a points-based system. Each API call consumes usage points, and your account has a total quota reset every hour. Complex batch requests that retrieve insights for many campaigns at once consume more points. The API returns error code 17 when you hit the account-level rate limit and error code 32 for API-level limits. To handle rate limits gracefully, implement exponential backoff: when you receive a 429 or a specific rate limit error code, wait progressively longer before retrying. The response headers include X-App-Usage and X-Ad-Account-Usage fields that show your current usage percentage β€” monitor these to adjust request frequency proactively. For deployment, choose Autoscale in Replit if your app serves a web dashboard that users interact with. Choose Reserved VM if you have a background process that regularly polls the Marketing API for campaign performance data. Facebook does not offer webhook notifications for campaign performance changes β€” polling is the standard approach. Deploy by clicking 'Deploy' in Replit. Your app gets a stable URL at https://your-app.replit.app, which you will need if you want to receive Meta webhook events for actions like lead form submissions.

rate_limited_client.py
1import os
2import time
3import requests
4from functools import wraps
5
6ACCESS_TOKEN = os.environ["FACEBOOK_ACCESS_TOKEN"]
7AD_ACCOUNT_ID = os.environ["FACEBOOK_AD_ACCOUNT_ID"]
8BASE_URL = "https://graph.facebook.com/v18.0"
9
10def with_retry(max_retries=3, initial_delay=1.0):
11 """Decorator for exponential backoff on rate limit errors."""
12 def decorator(func):
13 @wraps(func)
14 def wrapper(*args, **kwargs):
15 delay = initial_delay
16 for attempt in range(max_retries):
17 try:
18 return func(*args, **kwargs)
19 except requests.HTTPError as e:
20 status = e.response.status_code
21 error_code = e.response.json().get('error', {}).get('code', 0)
22 # Rate limit errors: 17 (app-level), 32 (account-level), 613
23 if status == 400 and error_code in [17, 32, 613] and attempt < max_retries - 1:
24 print(f"Rate limited. Waiting {delay}s before retry {attempt + 1}...")
25 time.sleep(delay)
26 delay *= 2 # Exponential backoff
27 else:
28 raise
29 return None
30 return wrapper
31 return decorator
32
33@with_retry(max_retries=3)
34def get_account_spend(date_preset: str = 'last_30d') -> dict:
35 """Fetch total account spend with rate limit handling."""
36 url = f"{BASE_URL}/{AD_ACCOUNT_ID}/insights"
37 params = {
38 'fields': 'spend,impressions,clicks,reach,actions',
39 'date_preset': date_preset,
40 'access_token': ACCESS_TOKEN
41 }
42 response = requests.get(url, params=params)
43 # Check rate limit usage headers
44 usage = response.headers.get('x-ad-account-usage', '')
45 if usage:
46 print(f"Ad account API usage: {usage}")
47 response.raise_for_status()
48 data = response.json().get('data', [])
49 return data[0] if data else {}
50
51if __name__ == '__main__':
52 spend_data = get_account_spend('last_7d')
53 print(f"Last 7 days spend: ${spend_data.get('spend', '0')}")
54 print(f"Impressions: {spend_data.get('impressions', '0')}")
55 print(f"Clicks: {spend_data.get('clicks', '0')}")

Pro tip: Monitor the x-app-usage and x-ad-account-usage headers in API responses. These return JSON strings like {"call_count": 15, "total_cputime": 5, "total_time": 8} showing percentage of quota used. Slow down requests when these values approach 80%.

Expected result: The script fetches account-level spend data for the past 7 days and prints usage metrics without triggering rate limit errors.

Common use cases

Automated Campaign Performance Dashboard

Build a Replit web app that pulls daily spend, impressions, clicks, and conversion metrics from all active campaigns in your Meta ad account and displays them on a custom dashboard. The dashboard can compare current performance to a prior period, flag campaigns where cost-per-result has increased beyond a defined threshold, and send Slack alerts when budget is nearly exhausted.

Replit Prompt

Build a Flask web app with a /campaigns endpoint that fetches all active Facebook campaigns from the Marketing API using FACEBOOK_ACCESS_TOKEN and FACEBOOK_AD_ACCOUNT_ID from Replit Secrets, retrieves spend and impressions insights for the past 7 days, and returns a JSON summary sorted by total spend.

Copy this prompt to try it in Replit

Automated Budget Pause Rules

Create a scheduled Replit script that checks ad set performance every hour and automatically pauses ad sets where the cost-per-result has exceeded a configurable maximum CPA (cost per acquisition). The script updates the ad set status to PAUSED via the Marketing API and logs the action with the reason for future auditing.

Replit Prompt

Write a Python script that fetches all active ad sets in a Facebook ad account, retrieves their cost_per_result insight for the last 3 days, and pauses any ad set where cost_per_result exceeds a MAX_CPA threshold stored in Replit Secrets, logging each action with the ad set name and reason.

Copy this prompt to try it in Replit

Custom Audience Sync from Your Database

Sync your app's customer email list to a Meta Custom Audience for retargeting. When users reach a specific milestone in your app (purchase, trial expiry, churn risk), your Replit backend hashes their email addresses with SHA-256, creates or updates a Custom Audience via the Marketing API, and adds the matched users for targeted ad delivery on Facebook and Instagram.

Replit Prompt

Build an Express endpoint that accepts an array of customer email addresses, hashes each with SHA-256, and calls the Facebook Marketing API to add them to a Custom Audience with ID FACEBOOK_CUSTOM_AUDIENCE_ID, using the /usersreplace endpoint to sync the current customer segment.

Copy this prompt to try it in Replit

Troubleshooting

API returns error code 190 β€” 'Invalid OAuth access token'

Cause: The access token stored in Replit Secrets has expired. Short-lived tokens expire after 1-2 hours, and long-lived tokens expire after 60 days of inactivity. System User tokens do not expire but can be invalidated if permissions are changed.

Solution: Generate a new access token in the Meta Graph API Explorer or via the long-lived token endpoint, and update FACEBOOK_ACCESS_TOKEN in Replit Secrets. For production use, implement a System User token which does not expire, or set up a token refresh flow using your app secret.

typescript
1# Python: Exchange short-lived token for long-lived token
2import requests
3
4def exchange_for_long_lived_token(short_lived_token: str) -> str:
5 params = {
6 'grant_type': 'fb_exchange_token',
7 'client_id': os.environ['FACEBOOK_APP_ID'],
8 'client_secret': os.environ['FACEBOOK_APP_SECRET'],
9 'fb_exchange_token': short_lived_token
10 }
11 response = requests.get('https://graph.facebook.com/v18.0/oauth/access_token', params=params)
12 return response.json()['access_token']

Error code 200 β€” 'Permission error: Requires ads_management permission'

Cause: The access token does not have the ads_management or ads_read permission scopes required for Marketing API operations. This happens when the token was generated without selecting these permissions in the Graph API Explorer.

Solution: In the Meta Graph API Explorer, click 'Generate Access Token' and make sure you select: ads_management, ads_read, and business_management permissions. If using a System User, go to Meta Business Manager > Business Settings > Users > System Users and ensure the user has Admin or Advertiser role on the relevant ad accounts.

Error code 17 β€” 'User request limit reached' when fetching insights

Cause: You are making too many API calls in a short period. The Marketing API enforces rate limits based on points, and insight requests for multiple campaigns can quickly exhaust the quota.

Solution: Implement exponential backoff with a minimum 1-second delay between insight requests. Batch related campaigns using the Async Insights Job API for large-scale reporting instead of making individual insight requests per campaign. The API supports requesting insights for an entire ad account at once.

typescript
1import time
2
3# Add delay between campaign insight requests
4for campaign_id in campaign_ids:
5 try:
6 insights = get_campaign_insights(campaign_id)
7 results.append(insights)
8 except Exception as e:
9 if 'limit reached' in str(e).lower():
10 time.sleep(60) # Wait 60 seconds on rate limit
11 else:
12 raise
13 time.sleep(0.5) # 500ms between requests

Insights endpoint returns empty data array even for active campaigns

Cause: The campaign has not generated any impressions in the requested date range, or the date_preset does not match the campaign's active period. Campaigns with very low budgets may show zero impressions for short date ranges.

Solution: Try a broader date range (last_30d or this_year) to confirm data exists. Also check that the campaign status is ACTIVE (not PAUSED) and that the ad account has a valid payment method with sufficient budget. Use the level parameter in insights requests to specify 'campaign', 'adset', or 'ad' to narrow the data scope.

typescript
1# Python: check campaign status before fetching insights
2campaign = Campaign(campaign_id)
3campaign_data = campaign.api_get(fields=['status', 'effective_status'])
4if campaign_data['effective_status'] != 'ACTIVE':
5 print(f"Campaign is not active: {campaign_data['effective_status']}")

Best practices

  • Store FACEBOOK_ACCESS_TOKEN, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET, and FACEBOOK_AD_ACCOUNT_ID in Replit Secrets (lock icon πŸ”’) β€” never in code or Git.
  • Use System User access tokens for production integrations β€” they do not expire and are not tied to a personal Facebook login that might lose access.
  • Always create new campaigns with status PAUSED in code β€” prevent accidental ad spend during development or testing.
  • Implement exponential backoff for all Marketing API requests to handle rate limit errors (error codes 17, 32, 613) gracefully without breaking your workflow.
  • Monitor x-app-usage and x-ad-account-usage response headers and throttle your request rate when usage approaches 75% of quota.
  • Never call the Facebook Marketing API from frontend JavaScript β€” always route requests through your Replit backend to keep access tokens secure.
  • Use Async Insights Jobs for large reporting queries that span many campaigns or long date ranges, rather than making synchronous per-campaign calls.
  • Deploy with Autoscale for dashboards and user-facing apps; use Reserved VM for background polling jobs that monitor campaign performance on a schedule.

Alternatives

Frequently asked questions

How do I store my Facebook access token in Replit?

Click the lock icon πŸ”’ in the left sidebar of your Replit project to open the Secrets pane. Add FACEBOOK_ACCESS_TOKEN with your token, FACEBOOK_AD_ACCOUNT_ID with your account ID (including the 'act_' prefix), and FACEBOOK_APP_ID and FACEBOOK_APP_SECRET from your Meta developer app settings. Access them in Python with os.environ['FACEBOOK_ACCESS_TOKEN'] and in Node.js with process.env.FACEBOOK_ACCESS_TOKEN.

How often does the Facebook access token expire?

Short-lived user tokens expire after 1-2 hours. Long-lived user tokens expire after 60 days of inactivity. System User tokens (the recommended approach for server-to-server integrations) do not expire but can be invalidated if the System User loses ad account permissions. Always use System User tokens for production Replit integrations to avoid unexpected authentication failures.

Can I create Facebook ads programmatically from Replit?

Yes. The Marketing API supports full campaign creation including campaigns, ad sets, ads, and creative assets. You need to create these in order: first the campaign, then an ad set within it, then an ad with a creative. Your Meta developer app must have ads_management permission, and the ad account must have a verified payment method. Always create campaigns with PAUSED status in code to prevent accidental spend during testing.

Does Replit work with the Facebook Marketing API on the free tier?

Yes. Replit's free tier supports outbound API calls, so you can call the Facebook Marketing API without a paid Replit plan. However, you will need Replit Core for always-on deployments if you want to run scheduled jobs that poll campaign performance regularly. The Facebook Marketing API itself is free to use β€” you only pay for the ad spend in your Meta ad account.

How do I handle the Facebook API rate limit in Replit?

The Marketing API returns error code 17 or 32 when you hit rate limits. Implement exponential backoff: catch these error codes, wait progressively longer (1s, 2s, 4s, 8s), and retry. Also monitor the x-app-usage and x-ad-account-usage response headers β€” they show your current usage percentage. Slow requests when usage exceeds 75%. For large reporting jobs, use Async Insights Jobs rather than synchronous calls.

What permissions does my Meta app need for the Marketing API?

For reading campaign data and insights, you need ads_read. For creating and modifying campaigns, ad sets, and ads, you need ads_management. For accessing Business Manager data (agencies managing multiple accounts), you also need business_management. Grant these when generating an access token in the Graph API Explorer, or assign them to your System User in Meta Business Manager.

RapidDev

Talk to an Expert

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

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation β€” no strings attached.

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.