Skip to main content

April 22, 2026 · 8 min read · How-to

DINEROUTE BLOG

Meta Conversions API for multi-location restaurants: a working setup

Single-location CAPI is well documented. The multi-location case is not. Here is the configuration we run for a four-location Thai/Vietnamese chain across one Pixel ID with per-location attribution intact.


Most Meta Conversions API documentation assumes you are a single ecommerce brand with one Pixel ID firing on one domain. Restaurant chains break that assumption immediately. You have one brand, multiple physical locations, often a mix of in-store ordering and third-party delivery, and a Pixel that needs to attribute events back to specific locations without fragmenting your audience.

There is no official Meta guide for this. We figured it out by setting it up for Malai Kitchen, a 4-location modern Thai/Vietnamese chain across Dallas-Fort Worth. This is the configuration we ship by default for every multi-location restaurant on DineRoute.

The architectural question: one Pixel or many?

You have two options when you run multiple locations.

Option A — one Pixel ID, per-location custom parameters. Every location fires events to the same Pixel, with a location_id parameter (southlake, uptown-dallas, etc.) attached as custom data. Your audience pool stays unified. Lookalikes are built off the brand. Per-location reporting requires custom breakdowns in Ads Manager but is fully possible.

Option B — one Pixel per location. Each location has its own Pixel ID and its own ad account. Reporting is clean per location. The audience pool fragments — you cannot easily build a lookalike from “all Malai Kitchen customers.” Lookalikes built off a single location have 10-25% as much training data.

For 99% of multi-location restaurants, Option A is correct. Audience pooling matters more than reporting purity, and per-location breakdowns are achievable with custom dimensions. The exceptions: franchises with separate ownership per location (each owner wants their own ad account), or brands with materially different cuisines across locations.

This guide assumes Option A.

Step 1: Configure the Pixel

Create one Pixel in Events Manager under your business account. Name it after the brand, not a location: “Malai Kitchen”, not “Malai Kitchen Southlake”. Install the Pixel base code on every page on every domain you control — primary website, ordering landing page, and any smart-link subdomain.

Generate a CAPI access token. In Events Manager, go to Settings → Conversions API → Generate access token. Treat it like a database password. Store it in your environment, never commit it to a repo.

Step 2: Define the events you’ll fire

Restaurant funnels have four useful events.

  1. PageView — standard, fires on every page load. Pixel + CAPI.
  2. ViewContent — fires on a menu or location page. Carries content_type: 'restaurant_location' and content_id: '{location_id}' as custom data.
  3. platform_click — fires when the diner taps “Order on DoorDash” or another platform. Custom event, not part of Meta’s standard taxonomy. Carries platform, location_id, order_type (pickup or delivery).
  4. InitiateCheckout — fires only if you operate direct ordering (Toast, ChowNow embed). Fires when the user starts an order on your owned ordering surface.

You do not fire Purchase. Purchase requires a confirmed order, which on third-party platforms you do not have. The closest you can fire is a webhook-based Purchase event from UberEats or ChowNow’s restaurant integrations, but that is a separate setup.

Step 3: Generate a single event_id per page session

The single most common multi-location CAPI mistake we see is duplicate event_ids across locations. Two diners at two locations both fire platform_click with event_id: 1 and Meta dedups them as one event.

The fix is to generate a UUID per page session, store it in a sessionStorage entry, and pass it to both the Pixel and CAPI for every event fired during that session.

Pseudocode that runs on every page load:

let eventId = sessionStorage.getItem('dr_event_id');
if (!eventId) {
  eventId = crypto.randomUUID();
  sessionStorage.setItem('dr_event_id', eventId);
}

For events fired later in the session (platform_click after PageView), generate a fresh UUID per event. The session-level ID is for matching PageView → CAPI; per-event UUIDs are for matching individual events → CAPI.

Step 4: Build the CAPI payload server-side

When a diner lands on a location page, your server captures:

  • IP address (from x-forwarded-for or the equivalent header)
  • User agent (from the request header)
  • Cookies: _fbp (browser session) and _fbc (click ID, set by Pixel from the fbclid URL parameter)
  • Event ID (from a query parameter the page passes back, or stored in a cookie)
  • Location ID (from the URL path: /southlakesouthlake)
  • Platform (only for platform_click: from the button the user tapped)

A minimal CAPI event for ViewContent looks like this:

POST https://graph.facebook.com/v18.0/{pixel_id}/events
{
  "access_token": "{your_token}",
  "data": [{
    "event_name": "ViewContent",
    "event_time": {unix_seconds},
    "event_id": "{uuid}",
    "action_source": "website",
    "event_source_url": "https://malai.dineroute.com/southlake",
    "user_data": {
      "client_ip_address": "{ip}",
      "client_user_agent": "{ua}",
      "fbc": "{_fbc cookie}",
      "fbp": "{_fbp cookie}"
    },
    "custom_data": {
      "content_type": "restaurant_location",
      "content_ids": ["southlake"],
      "location_id": "southlake"
    }
  }]
}

For platform_click, change event_name, drop content_type, and add platform and order_type in custom_data.

Step 5: Configure custom conversions in Events Manager

Once events start flowing, create custom conversions per location for the events that matter. The setup looks like this:

  1. Go to Events Manager → Custom Conversions → Create
  2. Name: “Platform Click — Southlake”
  3. Data source: your Pixel
  4. Rule: event_name equals platform_click AND custom_data.location_id equals southlake
  5. Category: Other (Meta does not have a “restaurant order intent” category)

Repeat per location. Now you can run a Meta campaign optimized for “Platform Click — Southlake” and the optimizer will look for the audience most likely to fire a platform_click event tagged with that specific location_id.

You can also create cross-location custom conversions: “Platform Click — Any Location” for brand-level campaigns, “Platform Click — DoorDash” for platform-level cohort analysis.

Step 6: Verify with the Events Manager test tool

Before launching paid traffic, verify the chain works end to end.

  1. Open Events Manager → Test Events.
  2. Get the test event code (a short alphanumeric like TEST12345).
  3. Add &test_event_code=TEST12345 to one CAPI call (or to the URL of the page that fires the event).
  4. Watch the test event tab. You should see PageView, ViewContent, and platform_click appear with full user_data fields populated.

If you see events appear with empty fbc or fbp, your Pixel is not setting cookies correctly — usually because the smart-link domain doesn’t have the Pixel base code installed. Fix that before scaling traffic.

Step 7: Audit Match Quality after one week of real traffic

Match Quality only stabilizes after a few hundred events fire. After a week of real traffic, open Events Manager → Data Sources → your Pixel → Diagnostics. You will see per-event Match Quality scores.

Expected scores for a properly configured restaurant smart-link, no PII:

  • PageView: 7-8
  • ViewContent: 7-8
  • platform_click: 7-9

If you are seeing 4-5, the most common causes are: IP not being captured server-side, user agent header truncated by a proxy, or _fbc cookie not present because the Pixel base code isn’t on the page.

Step 8: Build the Ads Manager dashboard

Set up a saved Ads Manager view with the following breakdowns:

  • Columns: Standard performance + custom conversion: Platform Click (Total) + per-platform custom conversions
  • Breakdown: By custom data field location_id (you may need to use the breakdown beta)
  • Date range: Last 28 days, default to compare with previous 28

The breakdown by location_id is the single most useful view for a multi-location restaurant. It tells you which locations are converting paid traffic and which are not, at the campaign or ad set level.

The piece nobody talks about

A clean multi-location CAPI setup will not save a campaign with a bad creative or a bad offer. The point is not to make Meta optimize a bad campaign better. The point is to make Meta capable of optimizing at all, because a Link Click campaign without server-side conversions is barely optimizing in any direction.

Once the chain is clean, you can run real experiments: per-location creative tests, per-platform offer tests, cross-location lookalike comparisons. Without the chain, every conclusion you draw from Ads Manager is downstream of bad data.

If you want a working reference implementation, every DineRoute multi-location restaurant runs exactly this setup. You can see it live at any malai.dineroute.com location page.

Related reading:


START FREE

Stop reading. Start measuring.

Every DineRoute restaurant fires Meta CAPI, Google Ads, GA4, and TikTok events server-side from day one. 14-day trial, no card.

No credit card. 14-day trial. Cancel any time.