---
title: 'fbp vs fbc vs fbclid: what each Meta identifier means'
description: 'Learn what fbclid means in a URL, how it becomes fbc, how fbp differs, and how to pass valid browser identifiers to Meta CAPI.'
canonical: 'https://plainrouter.com/library/fbp-fbc'
format: Explainer
published_at: '2026-09-03'
last_updated: '2026-10-29'
---

# fbp vs fbc vs fbclid: what each Meta identifier means

fbp identifies the browser and comes from the \_fbp first-party cookie. fbc records a Meta ad click and is built from the fbclid URL parameter. Send both to the Conversions API exactly as received, without hashing, when consent allows. If no click was captured, omit fbc.

## What does fbclid mean in a URL?

` fbclid ` is the case-sensitive click ID in a Meta ad's landing URL; it supplies the click-ID part of ` fbc `, not the complete value. For URL examples, missing parameters and when to remove it, read [fbclid: meaning and removal](</library/fbclid>).

## What should you send when fbc is missing?

Omit fbc when no permitted Meta click identifier is available. Keep sending legitimate fbp when consent allows; never invent fbc or use another visitor’s value.

If a real fbclid was captured but no \_fbc cookie exists, construct fbc with that click ID and its first-observed timestamp. Preserve an existing valid \_fbc value instead of rebuilding it with the later conversion time.

A fictional landing URL might look like this:

```text
https://shop.example/products/widget?fbclid=IwAR3ExampleClickIdentifier
```

Here, ` IwAR3ExampleClickIdentifier ` is the raw ` fbclid ` value. Meta's [official server SDK](<https://github.com/facebook/facebook-nodejs-business-sdk/blob/main/src/objects/serverside/user-data.js>) documents that ` fbc ` can come from the ` _fbc ` cookie or be generated from this URL parameter. Preserve the click's capture time when formatting it as ` fbc `; do not send the raw URL value as a complete ` fbc `.

[fbp and fbc are customer information parameters in Meta's Conversions API](<https://developers.facebook.com/documentation/ads-commerce/conversions-api/parameters/customer-information-parameters>). Send both unchanged, without hashing, when your consent policy permits their use. If no Meta click identifier was captured, omit ` fbc `.

For the browser-storage background, compare [first-party and third-party cookies](</definitions/first-party-cookies>) and see [how pixel tracking works](</definitions/pixel-tracking>).

## Key takeaways

- ` fbp ` describes browser context; ` fbc ` describes a Meta ad click.
- Send the original values unchanged. Do not SHA-256 hash either field.
- Never invent ` fbc ` when no ` fbclid ` was captured.
- Preserve the time when the click was first observed, not the later purchase time.
- In a Plainrouter event request, put both values under ` click_ids `, not ` user_data `.
- Capture, persist, and send them only when your consent policy permits it.

## What is the difference between fbp, fbc, and fbclid?

` _fbp ` and ` _fbc ` are cookie names; ` fbp ` and ` fbc ` are the corresponding CAPI field names. ` fbclid ` is the click ID in a landing-page URL, before it is combined with a timestamp to form ` fbc `.

| Field | Represents | Typical source | When it may be absent |
| --- | --- | --- | --- |
| ` fbp ` | A browser associated with a first-party Meta browser cookie. | The ` _fbp ` cookie created after permitted browser storage. | The browser blocks storage, consent is not granted, or no integration created it. |
| ` fbc ` | A captured Meta ad click associated with the visitor. | A landing-page ` fbclid `, combined with its capture time. | No permitted current or retained Meta click identifier is available. |
| ` fbclid ` | The raw click identifier added to a Meta ad landing URL. | The landing request's URL query string. | The URL has no Meta click parameter, or a redirect removed it. |

None of these identifiers identifies the conversion itself. Use ` event_id ` to identify one logical event and deduplicate its browser and server copies. Use ` fbp ` and ` fbc ` to provide permitted browser and click context for matching and attribution.

| Identifier | fbp | fbc | fbclid |
| --- | --- | --- | --- |
| What it identifies | Browser context | A captured Meta ad click | Raw Meta ad click ID |
| Source | The \_fbp first-party cookie | The \_fbc cookie, or a captured fbclid plus capture time | Landing URL query parameter |
| Base format | fb.\<domain index\>.\<creation time in ms\>.\<random number\> | fb.\<domain index\>.\<capture time in ms\>.\<fbclid\> | Opaque, case-sensitive URL value |
| Cookie lifetime | Not specified in the cited parameter guide; inspect your cookie settings | Meta recommends 90-day \_fbc expiry; browser restrictions can shorten it | Not a cookie; no cookie expiry of its own |
| How to send | Unhashed as Meta user\_data.fbp | Unhashed as Meta user\_data.fbc | Construct fbc from a real captured click; do not substitute the raw value |

Meta's [fbp/fbc parameter guide](<https://developers.facebook.com/documentation/ads-commerce/conversions-api/parameters/fbp-and-fbc>) defines the domain index and timestamps in the table. The domain index depends on the cookie domain; Meta specifies 1 for server formatting when no cookie is saved. [Parameter Builder values can carry an additional suffix](<https://developers.facebook.com/documentation/ads-commerce/conversions-api/parameter-builder-library>). Expiry recommendations do not override consent or guarantee retention.

## What format should fbp and fbc use?

Meta browser identifiers commonly use these structures:

```text
fbp: fb.1.<creation-time-milliseconds>.<random-decimal>
fbc: fb.1.<click-time-milliseconds>.<fbclid>
```

For example:

```text
fb.1.1786271000000.1234567890
fb.1.1786271000000.IwAR3ExampleClickIdentifier
```

The timestamp inside ` fbc ` belongs to the click capture. If the visitor purchases two days later, do not rebuild ` fbc ` with the purchase time. Keep the originally captured value.

An ` fbclid ` is not itself an ` fbc `. If you own the capture flow, record the time when the landing page first receives ` fbclid ` and construct the browser identifier at that boundary. Do not manufacture a placeholder for visits without one.

### Who sets \_fbp and \_fbc, and how long do they last?

When first-party cookies are enabled, the Meta Pixel creates ` _fbp ` on the website's domain if no value exists; the Pixel also saves available ad-click context in ` _fbc `. Meta documents [server-side formatting for both event parameters](<https://developers.facebook.com/documentation/ads-commerce/conversions-api/parameters/fbp-and-fbc>) and recommends setting formatted ` _fbc ` in the HTTP response with a 90-day expiry. A server can instead retain formatted click context in permitted backend storage.

Meta does not specify an ` _fbp ` expiry in that guide. Treat the 90-day ` _fbc ` recommendation as a requested expiry, not guaranteed browser retention. Check the actual cookie attributes and [browser-storage restrictions](</definitions/first-party-cookies>).

## How the values reach a server event

The two values can have different origins but travel with the same eligible event:

```text
Meta ad click ── fbclid + capture time ── fbc ──┐
                                                ├─ click_ids ─ Meta user_data
Consented browser storage ─────────────── fbp ──┘

Logical conversion ───────────────── event_id ── deduplication identity
```

This separation matters when debugging. A correct ` event_id ` does not compensate for missing match context, and a valid ` fbc ` does not deduplicate two copies of a purchase.

## How do you capture fbp and fbc after consent?

### Use the managed browser path

Plainrouter's generated Signals snippet can manage the browser values after full advertising consent. It captures an eligible ` fbclid `, creates or reads the browser identifier, and includes the available values with consented events. When consent is denied or withdrawn, Plainrouter-owned browser identifiers are not kept for later advertising delivery.

With that managed path, do not add your own competing ` _fbp ` or ` _fbc ` implementation. Track the business event once and let the configured destination use the eligible context:

```js
const eventId = await signalq('track', 'Purchase', {
    value: '49.90',
    currency: 'EUR',
    order_id: 'ORDER-1042',
});

console.log('Accepted event ID', eventId);
```

### Transfer existing cookies to your server

If your application sends the server event manually, read the browser values from the consenting request that belongs to the visitor. This helper preserves embedded ` = ` characters and ignores malformed cookie segments:

```ts
import type { IncomingMessage } from 'node:http';

function decodeCookiePart(value: string): string | undefined {
    try {
        return decodeURIComponent(value);
    } catch {
        return undefined;
    }
}

function readCookies(header: string | undefined): Record<string, string> {
    return Object.fromEntries(
        (header ?? '').split(';').flatMap((part) => {
            const separator = part.indexOf('=');

            if (separator <= 0) return [];

            const name = decodeCookiePart(part.slice(0, separator).trim());
            const value = decodeCookiePart(part.slice(separator + 1).trim());

            return name && value ? [[name, value] as const] : [];
        }),
    );
}

function readMetaClickIds(request: IncomingMessage) {
    const cookies = readCookies(request.headers.cookie);

    return {
        ...(cookies._fbp ? { fbp: cookies._fbp } : {}),
        ...(cookies._fbc ? { fbc: cookies._fbc } : {}),
    };
}
```

Use a reviewed cookie parser in a production framework when one is available. Do not put these values in URLs, analytics logs, or client-visible error reports just to move them between layers.

## Send the values through Plainrouter

The Plainrouter TypeScript SDK accepts advertising identifiers under ` click_ids `. Building on the helper above, this server handler carries only values present on the incoming request:

```ts
import type { IncomingMessage } from 'node:http';
import { configurePlainrouter, createEvent } from '@plainrouter/sdk';

const signalSecret = process.env.PLAINROUTER_SIGNAL_SECRET;

if (!signalSecret) {
    throw new Error('PLAINROUTER_SIGNAL_SECRET is required');
}

configurePlainrouter({ signalTrackerSecret: signalSecret });

export async function sendPurchase(request: IncomingMessage, order: { id: string; total: string }) {
    const clickIds = readMetaClickIds(request);

    const { data, response } = await createEvent({
        body: {
            event_id: `purchase:${order.id}`,
            event_name: 'Purchase',
            event_source: 'https://shop.example/checkout/success',
            action_source: 'website',
            consent_basis: 'consent',
            consent: {
                ad_storage: 'granted',
                ad_user_data: 'granted',
                ad_personalization: 'granted',
                captured_at: new Date().toISOString(),
                source: 'checkout_cmp',
            },
            click_ids: clickIds,
            value_data: {
                value: order.total,
                currency: 'EUR',
                order_id: order.id,
            },
        },
    });

    if (!data) {
        const status = response?.status ?? 'no HTTP response';
        throw new Error(`Event request failed: ${status}`);
    }

    return data;
}
```

The example assumes the consent object comes from the site's real consent workflow. Copying ` granted ` into a request does not establish permission by itself.

Plainrouter accepts Meta and other advertising identifiers under ` click_ids `. During eligible Meta delivery, valid ` fbp ` and ` fbc ` values become Meta ` user_data ` fields. Values that do not follow the expected Meta browser-ID shape are not useful delivery context.

## Should you hash fbp and fbc before sending them to Meta?

No. Meta expects ` fbp ` and ` fbc ` in their documented browser-ID formats rather than as SHA-256 hashes. Send valid values exactly as captured. The table below describes the Plainrouter API; direct Meta CAPI requests use Meta's own field names and hashing rules.

| Input | Plainrouter request location | Hash before sending? |
| --- | --- | --- |
| ` _fbp ` cookie value | ` click_ids.fbp ` | No |
| ` _fbc ` cookie value | ` click_ids.fbc ` | No |
| Email address | ` user_data.email ` | No; Plainrouter normalizes and hashes supported raw identity fields for Meta. |
| Phone number | ` user_data.phone ` | No; Plainrouter normalizes and hashes supported raw identity fields for Meta. |
| Event identity | ` event_id ` | No; use the same stable value for retries and paired delivery. |

Hashing ` fbp ` or ` fbc ` destroys the structure Meta expects. Placing them under ` user_data ` in the Plainrouter request also bypasses the public field contract; use ` click_ids `.

## What these values can and cannot improve

Available, valid browser context can help Meta associate a server event with a browser or ad click. It does not guarantee attribution, a particular Event Match Quality score, or a campaign outcome.

Do not optimize for field presence by fabricating identifiers. The correct state for a direct visit is often an ` fbp ` without ` fbc `. The correct state before permitted browser storage may be neither value.

## Common fbp and fbc mistakes

| Mistake | Why it fails | Better approach |
| --- | --- | --- |
| Hashing the values. | Meta no longer receives the expected browser-ID structure. | Send the captured values unchanged. |
| Treating ` fbclid ` as a ready-made ` fbc `. | The formatted identifier is missing its prefix and capture time. | Preserve the landing click and its original capture time. |
| Creating ` fbc ` for every visit. | Direct and non-Meta visits are falsely labeled as Meta clicks. | Omit ` fbc ` when no valid ` fbclid ` exists. |
| Rebuilding ` fbc ` at purchase time. | The timestamp no longer represents the ad click. | Reuse the value captured on landing. |
| Reading cookies before consent permits it. | Transport location does not replace the site's consent decision. | Gate capture and use through the real consent workflow. |
| Putting the values in ` user_data ` in a Plainrouter request. | The request no longer follows the public Plainrouter event shape. | Use ` click_ids.fbp ` and ` click_ids.fbc `. |
| Expecting them to deduplicate events. | They provide match context, not conversion identity. | Coordinate browser and server copies with ` event_id `. |

## How to debug missing browser identifiers

A missing ` fbc ` is only a capture problem if the visit supplied a Meta click identifier that your consent policy allowed you to retain. Check the landing request before changing the conversion payload.

To label the same ad visit in analytics, use [Facebook UTM parameters](</library/facebook-utm-parameters>) separately from the Meta click identifier.

1. Start with one known visit and record whether its landing URL actually contained ` fbclid `.
1. Confirm the site's resolved consent state before the identifiers are read or created.
1. Inspect ` _fbp ` and ` _fbc ` in browser storage. An absent ` _fbc ` is expected when no Meta click occurred.
1. Confirm the server request carries the original values under ` click_ids ` without hashing or reformatting.
1. Confirm the request belongs to the same visitor and is not coming from a background system with no browser context.
1. Inspect the accepted Plainrouter event and its destination delivery state separately.
1. Confirm the event is eligible for the configured Meta destination before treating missing downstream fields as a capture bug.
1. Use [Meta Test Events and Events Manager diagnostics](</library/meta-events-manager>) to inspect the received server event.

Debug the acquisition path and the conversion path separately. The click can be lost on the landing request even when the later purchase request is otherwise correct.

## Frequently asked questions

### Is fbp the same as a Meta Pixel ID?

No. A Pixel or dataset ID identifies the Meta data source. ` fbp ` is browser context associated with a visitor's first-party cookie.

### Is fbc always required for Meta CAPI?

No. ` fbc ` should be present only when a valid Meta click identifier was captured. A direct or organic visit can still carry a retained ` fbc ` from an earlier Meta click when your policy permits it. A visit without a current or retained Meta click identifier should not be assigned one.

### Can I send fbclid directly as fbc?

No. ` fbclid ` is only the click-ID portion. An ` fbc ` also includes the ` fb ` prefix, domain index, and original creation timestamp in milliseconds. Send the complete captured ` _fbc ` value, or construct the documented format when you capture an eligible landing-page click. Do not use the later purchase time.

### Can the server create fbp?

A server should normally transfer the value created in permitted browser context rather than inventing a browser identity during a backend job. If the request has no browser context, omit it.

### How long should I keep fbp and fbc?

Follow Meta's guidance, browser limits, and your consent and retention policy. Meta recommends a 90-day expiry for ` _fbc `; its parameter guide does not specify an ` _fbp ` expiry. See [Meta's parameter guidance](<https://developers.facebook.com/documentation/ads-commerce/conversions-api/parameters/fbp-and-fbc>) and check the actual browser cookie settings.

### Do fbp and fbc replace email or phone matching?

No. They provide browser and click context. Permitted customer information is a separate input with different normalization and hashing rules.

### Do fbp and fbc replace event\_id?

No. ` event_id ` identifies the logical conversion and coordinates retries or browser/server deduplication. ` fbp ` and ` fbc ` supply matching and attribution context.

## Sources

- [Meta: Conversions API customer information parameters](<https://developers.facebook.com/documentation/ads-commerce/conversions-api/parameters/customer-information-parameters>)
- [Meta: Conversions API server event parameters](<https://developers.facebook.com/documentation/ads-commerce/conversions-api/parameters/server-event>)
- [Meta Business SDK for Node.js](<https://github.com/facebook/facebook-nodejs-business-sdk#conversions-api>)
- [Plainrouter Conversion API reference](<https://plainrouter.com/docs/api/conversions>)
- [Plainrouter TypeScript SDK request types](<https://github.com/plainrouter/sdk/blob/v0.5.1/packages/sdk/src/generated/types.gen.ts>)

## Related guides

- 
    [Troubleshoot missing Meta Pixel and CAPI events](</library/meta-capi-missing-duplicate-events>)
    
- 
    [Meta Event Match Quality: diagnose a low or falling score](</library/meta-event-match-quality>)
    
- 
    [How does Meta event\_id deduplication work?](</library/meta-event-id-deduplication>)
    
- 
    [Can you use Meta CAPI without Google Tag Manager?](</library/meta-capi-without-gtm>)
    
- 
    [Track events and consent](<https://plainrouter.com/docs/signals/track-events>)
    
- 
    [How does consent work for server-side tracking?](</library/server-side-consent>)
    

## Inspect browser identifiers locally

The interactive version of this guide includes an fbp/fbc decoder below. Paste a bare value or ` _fbp= ` / ` _fbc= ` cookie value to check its shape and timestamp. The check stays in your browser and does not verify attribution.

To construct fbc from a real captured fbclid, supply the original capture time in Unix milliseconds and the subdomain index for the cookie domain. Do not use the purchase time or invent an identifier for a visit without a captured click.
