Skip to main content
RapidDev - Software Development Agency
lovable-integrationsEdge Function Integration

How to Integrate Lovable with Facebook Ads

To build a Facebook Ads performance dashboard in Lovable, create a Meta system user token with Marketing API access, store it in Cloud → Secrets, and build Edge Functions that proxy Meta Marketing API calls for campaign metrics, ad set performance, and audience insights. Unlike Google Ads (which uses OAuth + developer token), Meta's system user token approach enables stable server-to-server access without user OAuth flows.

What you'll learn

  • How to create a Meta system user and generate a long-lived access token for Marketing API access
  • How to store your Meta access token securely in Lovable Cloud → Secrets
  • How to write Edge Functions that fetch campaign metrics, ad set performance, and audience data from the Meta Marketing API
  • How to build a visual ad performance dashboard in Lovable with React charts
  • The difference between Meta Marketing API system user tokens and user OAuth tokens, and why system user tokens are better for server-side dashboards
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read35 minutesSocialMarch 2026RapidDev Engineering Team
TL;DR

To build a Facebook Ads performance dashboard in Lovable, create a Meta system user token with Marketing API access, store it in Cloud → Secrets, and build Edge Functions that proxy Meta Marketing API calls for campaign metrics, ad set performance, and audience insights. Unlike Google Ads (which uses OAuth + developer token), Meta's system user token approach enables stable server-to-server access without user OAuth flows.

Build Meta Ads performance dashboards in Lovable using Marketing API Edge Functions

Meta Ads (Facebook and Instagram) is one of the highest-spend advertising channels for digital businesses, but Meta's native Ads Manager presents data in formats that rarely match exactly what a marketing team, agency, or founder needs for their specific reporting workflow. Custom dashboards built in Lovable solve this — pulling live ad performance data from Meta's Marketing API and presenting it in the exact format, time range, and metric groupings that drive faster decisions.

The Meta Marketing API provides: campaign-level metrics (spend, impressions, reach, clicks, conversions), ad set performance (CPM, CPC, CTR, frequency), ad creative performance (which variants are winning), audience demographic breakdowns, and placement performance (Facebook feed vs Instagram feed vs Stories vs Reels). All of this is accessible via Edge Functions that proxy Marketing API calls with a stored access token.

For stable dashboard access without OAuth complexity, Meta Business Manager's system user tokens are the right choice. System users are server-side identities that hold access tokens indefinitely (or for 60 days for regular tokens), avoiding the access token expiry issues that plague user OAuth implementations. The Edge Function reads the system user token from Cloud → Secrets and passes it as a query parameter (Meta's Marketing API uses access_token as a query parameter, not a Bearer header by default).

Integration method

Edge Function Integration

Meta Marketing API has no native Lovable connector. Ad performance data is retrieved via Lovable Edge Functions that proxy Meta Marketing API calls. A long-lived system user token (generated in Meta Business Manager) is stored in Cloud → Secrets and passed as the Bearer token in all API requests via Deno.env.get(), keeping credentials server-side and enabling stable dashboard access without OAuth token refresh complexity.

Prerequisites

  • A Lovable project with at least one deployed app (Edge Functions require Lovable Cloud)
  • A Meta Business Manager account (business.facebook.com) with admin access to the ad account you want to pull data from
  • A Meta Developer App (developers.facebook.com) with Marketing API access enabled
  • Ability to create system users in Meta Business Manager (Business Settings → Users → System Users)
  • The Meta Ad Account ID you want to pull performance data from (visible in Meta Ads Manager in the account list)

Step-by-step guide

1

Create a Meta system user and generate a long-lived access token

System users in Meta Business Manager are server-side identities that hold access tokens for automated processes. Unlike regular user tokens that expire frequently, system user tokens can be generated with 60-day or non-expiring lifetimes — essential for a stable reporting dashboard. In Meta Business Manager (business.facebook.com): go to Business Settings → Users → System Users. Click 'Add'. Give the system user a name like 'Lovable Dashboard' and set the role to 'Employee' (not Admin — follow least privilege). Click 'Create system user'. After creation, click 'Add Assets' to grant the system user access to your ad account. Select 'Ad accounts' → find your ad account → check 'Manage campaigns' (or 'View performance' if read-only access is sufficient for a dashboard). Click Save Changes. Next, generate an access token: select the system user → click 'Generate new token'. Choose your Meta App from the dropdown (the same app where Marketing API is enabled). Select the following permissions: ads_read (to read campaign and ad performance), ads_management (if you also want to manage campaigns, not just read), business_management (to access business-level data). Set the token expiry — for a dashboard, choose 'Never' if your Meta App has been approved for non-expiring tokens, or 60 days otherwise. Copy the generated token immediately — it will not be shown again. This is your META_ACCESS_TOKEN secret value. Also note your Ad Account ID: in Meta Ads Manager, click the account selector dropdown — the ID starts with 'act_' (e.g., act_123456789). Store this as META_AD_ACCOUNT_ID.

Pro tip: For a read-only reporting dashboard, grant the system user only 'View performance' access to the ad account and only request the ads_read permission on the token. This limits the impact of a compromised token.

Expected result: A system user is created in Meta Business Manager with access to your ad account. A long-lived access token is generated and copied. Your Ad Account ID (act_XXXXXXXXX) is noted.

2

Add Meta credentials to Lovable Cloud Secrets

Store your Meta credentials in Lovable's Cloud Secrets panel. The system user access token grants access to your ad account data — keep it server-side in Edge Functions, never in frontend code. In Lovable, click '+' → Cloud panel → Secrets tab. Add the following secrets: META_ACCESS_TOKEN: your system user access token (a long alphanumeric string starting with 'EAAN' or similar Meta token prefix) META_AD_ACCOUNT_ID: your ad account ID including the 'act_' prefix (e.g., act_123456789) Optionally add META_APP_ID and META_APP_SECRET if your Edge Functions will need to generate user tokens or perform app-level API calls beyond account insights. With these secrets saved, your Edge Functions can authenticate to the Meta Marketing API using the access_token query parameter.

Pro tip: If you manage multiple Meta ad accounts (for an agency or multi-brand business), store each account ID separately: META_AD_ACCOUNT_ID_BRAND_A, META_AD_ACCOUNT_ID_BRAND_B. Your Edge Function can accept an account parameter and select the appropriate secret.

Expected result: META_ACCESS_TOKEN and META_AD_ACCOUNT_ID appear in Cloud → Secrets with masked values.

3

Create the Meta Marketing API campaigns Edge Function

Create the Edge Function that fetches campaign performance data from Meta's Marketing API. Meta's API uses a Graph API structure — endpoints are at graph.facebook.com/v18.0/{objectId}/{edge}. For campaign insights, you call /{adAccountId}/campaigns to get campaign IDs, then /{campaignId}/insights with the fields and date range you want. Meta Marketing API uses access_token as a query parameter (or Authorization: Bearer header — both work, but query parameter is more common in Meta's documentation). The insights endpoint supports powerful filtering with time_range parameter, date_preset values (today, yesterday, last_7_days, last_30_days, last_month, this_month), and breakdowns for demographic and placement segmentation. Key insight fields for a performance dashboard: campaign_name, spend, impressions, clicks, reach, frequency, cpm, cpc, ctr, actions (conversions), cost_per_action_type (CPA). For conversion data, actions is an array of action types — filter for the specific conversion event relevant to your business (purchase, lead, page_view, etc.). The code below shows a complete campaign insights fetch with date range support. Meta's API returns paginated results using cursor-based pagination — the next_cursor in the paging.cursors object lets you fetch subsequent pages.

Lovable Prompt

Create an Edge Function called meta-campaigns at supabase/functions/meta-campaigns/index.ts. It should use META_ACCESS_TOKEN and META_AD_ACCOUNT_ID from secrets. Accept a POST request with { datePreset, startDate, endDate } — use datePreset (e.g., 'last_30_days') if provided, otherwise use startDate/endDate range. Call the Meta Marketing API v18 to fetch all campaigns with insights: campaign_name, spend, impressions, clicks, ctr, cpc, actions, cost_per_action_type. Return normalized campaign data sorted by spend descending. Include CORS headers.

Paste this in Lovable chat

supabase/functions/meta-campaigns/index.ts
1import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
2
3const corsHeaders = {
4 'Access-Control-Allow-Origin': '*',
5 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
6}
7
8const GRAPH_API_BASE = 'https://graph.facebook.com/v18.0'
9
10serve(async (req) => {
11 if (req.method === 'OPTIONS') {
12 return new Response('ok', { headers: corsHeaders })
13 }
14
15 try {
16 const { datePreset = 'last_30_days', startDate, endDate } = await req.json().catch(() => ({}))
17
18 const accessToken = Deno.env.get('META_ACCESS_TOKEN')
19 const adAccountId = Deno.env.get('META_AD_ACCOUNT_ID')
20
21 if (!accessToken || !adAccountId) {
22 throw new Error('Missing Meta secrets: META_ACCESS_TOKEN and META_AD_ACCOUNT_ID required')
23 }
24
25 // Build time range parameter
26 const timeRange = startDate && endDate
27 ? `&time_range={"since":"${startDate}","until":"${endDate}"}`
28 : `&date_preset=${datePreset}`
29
30 // Fetch campaign insights
31 const fields = [
32 'campaign_name',
33 'campaign_id',
34 'spend',
35 'impressions',
36 'clicks',
37 'reach',
38 'ctr',
39 'cpc',
40 'cpm',
41 'frequency',
42 'actions',
43 'cost_per_action_type',
44 ].join(',')
45
46 const insightsUrl = `${GRAPH_API_BASE}/${adAccountId}/insights` +
47 `?fields=${encodeURIComponent(fields)}` +
48 `&level=campaign` +
49 timeRange +
50 `&access_token=${accessToken}` +
51 `&limit=50`
52
53 const response = await fetch(insightsUrl)
54 const data = await response.json()
55
56 if (!response.ok || data.error) {
57 throw new Error(`Meta API error: ${data.error?.message || JSON.stringify(data)}`)
58 }
59
60 // Normalize the response
61 const campaigns = (data.data || []).map((item: Record<string, unknown>) => {
62 const actions = (item.actions as Array<{ action_type: string; value: string }>) || []
63 const purchases = actions.find((a) => a.action_type === 'purchase')
64 const leads = actions.find((a) => a.action_type === 'lead')
65
66 return {
67 campaignId: item.campaign_id,
68 campaignName: item.campaign_name,
69 spend: parseFloat(item.spend as string || '0'),
70 impressions: parseInt(item.impressions as string || '0', 10),
71 clicks: parseInt(item.clicks as string || '0', 10),
72 reach: parseInt(item.reach as string || '0', 10),
73 ctr: parseFloat(item.ctr as string || '0'),
74 cpc: parseFloat(item.cpc as string || '0'),
75 cpm: parseFloat(item.cpm as string || '0'),
76 frequency: parseFloat(item.frequency as string || '0'),
77 purchases: purchases ? parseInt(purchases.value, 10) : 0,
78 leads: leads ? parseInt(leads.value, 10) : 0,
79 }
80 }).sort((a: { spend: number }, b: { spend: number }) => b.spend - a.spend)
81
82 return new Response(
83 JSON.stringify({ campaigns, total: campaigns.length }),
84 { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
85 )
86 } catch (error) {
87 return new Response(
88 JSON.stringify({ error: error.message }),
89 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
90 )
91 }
92})

Pro tip: Meta Marketing API returns financial values as strings, not numbers. Always use parseFloat() on spend, cpc, cpm, and ctr values before arithmetic operations or chart rendering.

Expected result: The meta-campaigns Edge Function is deployed. Test it from Cloud → Edge Functions with a POST request containing { datePreset: 'last_7_days' }. The response should include your active campaigns with spend and performance data.

4

Build the ads performance dashboard in Lovable React

With the Edge Function deployed, build the dashboard UI that visualizes your Meta ad performance. Use supabase.functions.invoke() to call the meta-campaigns Edge Function with date range parameters, then render the data as charts and tables. For the dashboard layout: a header row with total spend, total impressions, average CTR, and total conversions as summary cards; a date range picker that triggers a fresh data fetch; a sortable data table with one row per campaign; and optionally a bar chart or line chart for spend trends over time. For charting, Lovable's AI can generate Recharts or Chart.js based visualizations from a description of the data shape. A BarChart with campaign names on the X axis and spend on the Y axis is the most common starting point. For daily spend trend data (to see how spend progresses through the month), you need a second Edge Function that calls the same insights endpoint but with the time_increment=1 (daily) parameter instead of a summary. Each day becomes one data point in the time series. For complex multi-account dashboard setups spanning multiple brands or client accounts, RapidDev's team can help architect an Edge Function design that handles account switching, caching, and proper data normalization across different Meta account structures.

Lovable Prompt

Create an ad performance dashboard page that calls the meta-campaigns Edge Function with datePreset='last_30_days'. Show summary cards for total spend, total impressions, total clicks, and average CTR. Then show a sortable table with all campaigns: name, spend, impressions, clicks, CTR, CPC, and conversions. Add a date preset selector (Last 7 days, Last 30 days, Last 90 days) that refreshes the data. Format spend and CPC as currency, CTR as percentage. Use loading skeleton states while fetching.

Paste this in Lovable chat

Pro tip: For ROAS (Return on Ad Spend) calculation, you need conversion revenue data. Meta's Marketing API includes purchase conversion value in the action_values field alongside the actions array — add 'action_values' to your insights fields list and look for the 'purchase' action_type to get total revenue driven by the campaign.

Expected result: The ads dashboard loads with real campaign data from your Meta ad account. Summary cards show aggregate spend, impressions, and clicks. The campaigns table is sortable. Changing the date preset refreshes the data from Meta's API.

Common use cases

Build a cross-campaign ROI dashboard for a marketing team

Create a dashboard that shows all active Meta campaigns side-by-side with spend, ROAS, CPA, and conversion counts for a custom date range. Edge Functions fetch campaign insights from Meta's Marketing API with the account ID and date range, aggregate the data, and the React frontend renders it as a sortable table with trend indicators.

Lovable Prompt

Create an Edge Function called meta-campaigns that fetches all active campaigns from a Meta ad account using META_ACCESS_TOKEN and META_AD_ACCOUNT_ID from secrets. Use the Meta Marketing API v18 to fetch campaign insights with fields: campaign_name, spend, impressions, clicks, actions, cost_per_action_type for a date range from the request body. Return normalized campaign performance data. Then create a dashboard page with a date range picker and a sortable table of campaign performance.

Copy this prompt to try it in Lovable

Show daily ad spend trend with budget pacing alerts

Build a daily spend trend chart that compares actual spend against the monthly budget target. The Edge Function fetches daily breakdown data from Meta's Marketing API, calculates budget pacing (are you on track to hit your monthly budget or over/underspending?), and the React component displays a line chart with a projected spend line and a visual alert when spend deviates more than 20% from the target pace.

Lovable Prompt

Create an Edge Function called meta-spend-trend that fetches daily spend data for the current month from Meta Marketing API using META_ACCESS_TOKEN and META_AD_ACCOUNT_ID. Use the breakdown=time_increment,day parameter to get daily data. Calculate budget pacing percentage given a monthly budget from the request. Return daily spend array and pacing status. Create a line chart page showing daily spend vs target with a pacing indicator badge.

Copy this prompt to try it in Lovable

Build an ad creative performance comparison view

Create a side-by-side comparison of ad creative performance — showing which image, video, or copy variations are driving the best CTR and conversion rates. The Edge Function fetches ad-level insights including creative thumbnails, and the React component displays them in a visual grid sorted by performance metric, giving the creative team instant feedback on what is working.

Lovable Prompt

Create an Edge Function called meta-ad-performance that fetches all ads in a campaign with their creative thumbnails and performance metrics (CTR, CPC, spend, conversions) using META_ACCESS_TOKEN from secrets. Accept campaignId in the request body. Call the Meta Marketing API ads endpoint with thumbnail_url, creative, and insight fields. Return ads sorted by CTR descending. Create a creative performance grid page showing ad thumbnails with overlaid performance stats.

Copy this prompt to try it in Lovable

Troubleshooting

Meta API returns error code 190: 'Invalid OAuth 2.0 Access Token'

Cause: The access token has expired (60-day tokens expire), been revoked, or the token stored in META_ACCESS_TOKEN is incorrect.

Solution: Go to Meta Business Manager → System Users → your system user → Generate new token. Generate a new access token and update META_ACCESS_TOKEN in Cloud → Secrets. Then redeploy the Edge Function. To avoid future expiry issues, check if your Meta App is eligible for non-expiring system user tokens (available on apps with Business verification) and generate one.

Meta API returns error code 200: 'Permissions Error — The user does not have permissions to access this data'

Cause: The system user was not granted access to the specific ad account, or the token was generated without the ads_read permission scope.

Solution: In Meta Business Manager → System Users → your system user → click 'Add Assets'. Find the ad account and grant 'Manage campaigns' or 'View performance'. Then regenerate the access token and ensure ads_read is selected in the permissions. Update META_ACCESS_TOKEN in Cloud → Secrets with the new token.

Meta Marketing API returns empty data array even though campaigns are active

Cause: The date range used in the API call does not overlap with the campaign's active period, or the campaign has no spend in the selected date range.

Solution: Try the date_preset=last_90_days parameter to cast a wider net. Also verify the campaign is actively running and has spent budget in the selected period by checking Meta Ads Manager. If you recently created the campaign, note that Meta's API may have a few hours delay in reflecting very recent activity. Also ensure your Edge Function is using the correct ad account ID (META_AD_ACCOUNT_ID) — a wrong account ID returns an empty dataset, not an error.

Dashboard loads but conversion (purchase/lead) counts show 0 for all campaigns

Cause: The actions field is present but the specific action_type being searched ('purchase' or 'lead') does not match the conversion events configured in your Meta Pixel or Conversions API setup.

Solution: In Meta Events Manager, check what conversion events are being tracked by your Meta Pixel — the event names there correspond to action_type values in the API. Common action types: 'purchase', 'lead', 'add_to_cart', 'initiate_checkout', 'complete_registration'. Log the full actions array from your Edge Function response to see exactly what action types are present, then update your normalization code to use the correct action_type name.

typescript
1// Log the raw actions to find your conversion event name:
2console.log('Available action types:', actions.map(a => a.action_type))
3// Then filter for the right one:
4const conversions = actions.find((a) => a.action_type === 'YOUR_EVENT_NAME')

Best practices

  • Use Meta Business Manager system user tokens instead of personal user tokens for server-side dashboards — system user tokens are stable, can be non-expiring, and represent the server process rather than a specific human user.
  • Request only the minimum ad account permissions needed for your use case — 'View performance' is sufficient for read-only dashboards, and limiting permissions reduces risk if a token is compromised.
  • Cache Meta Marketing API responses in Supabase with a 15-30 minute TTL — Meta's API has rate limits (approximately 200 calls/hour per ad account), and frequent dashboard refreshes can quickly consume quota.
  • Always parse Meta API financial values (spend, cpc, cpm) as floats with parseFloat() — Meta returns all numeric values as strings in the JSON response.
  • Include error handling for Meta's specific error codes — code 190 means token expired/invalid, code 200 means permissions error, code 17 means rate limited. Different error codes require different UI responses.
  • For multi-client agency dashboards, implement a secure account selection mechanism in your Supabase database rather than hardcoding each client's ad account ID — store client configurations and select the appropriate account based on the authenticated user's permissions.
  • Monitor your Meta Marketing API rate limit consumption in the X-App-Usage and X-Ad-Account-Usage headers returned with each API response — proactively reduce call frequency if you approach the limits.

Alternatives

Frequently asked questions

Do I need a Meta Developer App to access the Marketing API?

Yes — you need a Meta Developer App registered at developers.facebook.com with the Marketing API product added. Go to your Meta Developer App → Add Products → Marketing API. For basic access (reading your own ad account data), the Marketing API is available immediately after enabling it. For advanced access (accessing other businesses' ad accounts as an agency) or to remove usage limits, Meta's app review process is required.

What is the difference between Meta system user tokens and regular user OAuth tokens?

Regular user OAuth tokens are tied to a specific Facebook user's account and expire when the user's session expires or they change their password — typically every 60 days at most. System user tokens are tied to a Business Manager system user (a non-human account), can be set to never expire (for apps with Business verification), and are not affected by individual user account changes. For a stable reporting dashboard, system user tokens are significantly more reliable.

How do I access Meta ads data for multiple clients or ad accounts?

For an agency dashboard with multiple client ad accounts, create a system user in each client's Business Manager and store each token as a separate secret (META_TOKEN_CLIENT_A, META_TOKEN_CLIENT_B, etc.) alongside each account ID. Your Edge Function can accept a clientId parameter and select the appropriate secret pair based on the logged-in user's client association stored in your Supabase database. This requires proper access control on the Edge Function to ensure users can only see their authorized accounts.

Why does Meta return financial values as strings instead of numbers?

Meta's Marketing API returns all currency and decimal values as strings to avoid floating-point precision issues in JavaScript — currency values need exact decimal representation that floating-point numbers cannot guarantee. Always use parseFloat() or parseFloat().toFixed(2) when processing spend, CPC, CPM, and CTR values. For currency display, use JavaScript's Intl.NumberFormat with the USD or appropriate currency code for formatted output.

Can I use this integration to also create and manage ads, not just read performance data?

Yes — Meta's Marketing API supports full campaign management: creating campaigns, ad sets, and ads; updating budgets, bids, and targeting; pausing and activating campaigns; and managing creatives. The same Edge Function pattern applies — add the appropriate management operations to your Edge Functions using POST and UPDATE calls to the Marketing API. The system user token needs ads_management permission (not just ads_read) for management operations.

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.