Home › How-tos › The Secret Setups › Meta
How to set up the Meta Conversions API with event deduplication
Live guide · Checked 28 October 2026 · Updated 28 October 2026 · Checked every week against Meta's own help pages
Send leads to Meta from your server as well as the browser, using the same event ID, so Meta counts every lead once, even when ad blockers or iPhones hide the pixel.
- Time
- 40 minutes
- You will need
- The Meta Pixel sending Lead with an eventID (previous Secret Setup)
- A server, CRM or automation tool that can send a web request when a lead arrives
- Admin access to Meta Events Manager
- Stuck?
- Troubleshooting or ask us a question
Step by step
Make an access token
In Meta Events Manager, open your pixel > Settings, scroll to Conversions API and click Generate access token. Copy it and keep it somewhere safe, like a password: never put it in your site's code.
Or use a no-code setup first
In the same place, Set up with Conversions API Gateway or a partner (Shopify, WordPress, HubSpot and others) does this without code. If your platform is listed, use it and skip to the dedup check. The steps below are for your own server.
Send the lead from your server
When a lead arrives on your server, send it to Meta. Use the same lead_id you pushed to the dataLayer as event_id:
// Node 18+ (or a Cloudflare Worker). Hash personal details with SHA-256 first. const sha = async (s) => [...new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s.trim().toLowerCase())))].map(b => b.toString(16).padStart(2, '0')).join(''); await fetch('https://graph.facebook.com/v21.0/YOUR_PIXEL_ID/events?access_token=' + process.env.META_CAPI_TOKEN, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ data: [{ event_name: 'Lead', // must match the browser event name exactly event_time: Math.floor(Date.now() / 1000), event_id: lead.lead_id, // the same id the pixel sent as eventID action_source: 'website', event_source_url: lead.page_url, user_data: { em: [await sha(lead.email)], ph: lead.phone ? [await sha(lead.phone.replace(/\D/g, ''))] : undefined, client_ip_address: lead.ip, client_user_agent: lead.user_agent, fbp: lead.fbp, // the _fbp cookie fbc: lead.fbc // the _fbc cookie, if there is one }, custom_data: { value: lead.value, currency: 'GBP' } }] }) });Send the lead_id and cookies with the form
Your server needs the lead_id and Meta's cookies from the browser. Add hidden fields
lead_id,fbpandfbcto the form and fill them before it's sent:function cookie(n) { return (document.cookie.match('(^|; )' + n + '=([^;]*)') || [])[2] || ''; } var id = 'L-' + Date.now(); document.querySelectorAll('form').forEach(function (f) { f.addEventListener('submit', function () { [['lead_id', id], ['fbp', cookie('_fbp')], ['fbc', cookie('_fbc')]].forEach(function (p) { var el = f.querySelector('input[name="' + p[0] + '"]'); if (el) el.value = p[1]; }); }); });Use the same
idin your dataLayer push, so the browser and server copies match.Test with a test code
In Events Manager open Test events and copy the test event code (like
TEST12345). Add"test_event_code": "TEST12345"next todatain the request, send a test lead and watch it appear marked Server. Remove the test code after.Check deduplication
Send a real test lead with the pixel on. In Events Manager > Overview, click Lead: after a few hours it shows Browser and Server with a Deduplicated note. If the counts double instead, the event names or IDs don't match.
Watch Event Match Quality
On the same page, Event Match Quality shows how well Meta matches your leads to people. Sending email, phone, fbp and fbc usually gets it to Good or Great.
Tips from people who set these up every week
- event_name and event_id must match exactly between browser and server, or Meta counts the lead twice.
- Send server events within an hour of the browser event: Meta only dedups inside a 48-hour window and works best when they're close.
Troubleshooting: questions and answers
Server events show but browser ones don't.
That's normal for people with ad blockers or who declined cookies. Make sure the server only sends for people who gave consent, if your banner requires it for marketing.
The API says the token is invalid.
Tokens can be revoked when a user leaves the business. Generate a new one from a system user in Business Settings for a token that doesn't expire.
Official help pages
Let Claude fix the rest of your funnel
Lead Focus is 12 Claude Skills that find the stage of your funnel that's costing you leads, then fix it: ads, landing pages, follow-ups and tracking. One payment, 12 months of updates, and a 14-day refund.
Get Lead Focus · $29.99Still stuck, or have a question?
Tell us where you got to and what you see. We read every message and reply by email, usually the same working day.