כך שולחים כל המרה פעמיים, וסופרים אותה פעם אחת
שני ערוצי מדידה עדיפים על אחד, אבל רק אם Meta יודעת שמדובר באותה המרה. המדריך הזה מחבר את הפיקסל בדפדפן ואת ה-Conversions API בשרת דרך event_id משותף, כך שכל רכישה נשלחת פעמיים ונספרת פעם אחת. זה השלב שבו כל אירועי המסחר מתחברים למדידה מלאה, בדפדפן ובשרת.
Purchase) עם אותו event_id (מבוסס מזהה ההזמנה). Meta מזהה את ההתאמה תוך 48 שעות ומדדפת, כך שמקבלים את החוסן של השרת בלי ספירה כפולה, ומקבלים תמונה מלאה יותר של ההמרות שאבדו במדידת הדפדפן בלבד.הפיקסל של Meta רץ בדפדפן, ולכן הוא הדבר הראשון שנשבר: חוסמי פרסומות, הגבלות iOS, וסירוב לעוגיות משאירים חלק מההמרות בחוץ. Conversions API (CAPI) שולח את אותן המרות מהשרת, במסלול שלא נחסם. הרעיון של 2026 הוא להריץ את שניהם יחד, ולדדפ ביניהם.
אבל אם שולחים את אותה רכישה גם מהדפדפן וגם מהשרת, Meta עלולה לספור אותה פעמיים. הפתרון הוא event_id משותף:
event_id יציב. עכשיו אפשר לראות למה, אותו מזהה עובר עם האירוע לאורך כל הדרך, ומאפשר לחבר בין הדפדפן לשרת בלי כפילויות. להעמקה בתפיסה: Facebook CAPI לעומק.events_management (Events Manager ← Settings ← Conversions API ← Generate Access Token).event_id בפורמט order_<id>._fbc, ו-_fbp נוצר על ידי הפיקסל.הפיקסל כבר שולח Purchase. הדבר היחיד שמוסיפים הוא eventID זהה למזהה ההזמנה, כדי ש-Meta תוכל לזהות אותו מול אירוע השרת:
<!-- בדפדפן, בעמוד אישור ההזמנה (Order Received). -->
<!-- ה-eventID חייב להיות זהה ל-event_id שהשרת שולח: 'order_' + מזהה ההזמנה. -->
<script>
fbq('track', 'Purchase', {
value: 349.90,
currency: 'ILS',
content_type: 'product',
contents: [{ id: 'SKU-1', quantity: 1 }]
}, { eventID: 'order_123' });
</script>בהגדרת GTM, ה-eventID נלקח מה-dataLayer: order_ ועוד ה-transaction_id שמדריך הרכישה כבר דוחף. כך אין צורך לקודד מזהה ידנית.
עכשיו שולחים את אותה רכישה מהשרת, עם אותו event_id בדיוק. הכלל פשוט: מידע שמזהה אדם עובר גיבוב (hashed), ומידע טכני שמזהה את הביקור לא. לכן האימייל והטלפון מגובבים, ואילו fbp ו-fbc נשלחים גלמיים:
/**
* Send the same Purchase to Meta from the SERVER (Conversions API),
* with the SAME event_id as the browser Pixel, so Meta deduplicates.
*/
add_action( 'woocommerce_thankyou', 'doffice_meta_capi_purchase', 20, 1 );
function doffice_meta_capi_purchase( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
// Send once per order (guards against page refresh / duplicate hooks).
if ( $order->get_meta( '_doffice_capi_sent' ) ) {
return;
}
$dataset_id = 'YOUR_DATASET_ID'; // = the Pixel ID
$access_token = 'YOUR_CAPI_ACCESS_TOKEN'; // token with events_management permission
$api_version = 'v21.0';
// SAME id as the browser Pixel and the purchase guide: order-based, unique per sale.
$event_id = 'order_' . $order->get_id();
// ---- user_data: HASH the PII (SHA-256, after normalizing); keep fbp/fbc/ip/ua RAW ----
$user_data = array();
if ( $order->get_billing_email() ) {
$email = strtolower( trim( $order->get_billing_email() ) ); // normalize first
$user_data['em'] = array( hash( 'sha256', $email ) );
}
if ( $order->get_billing_phone() ) {
$phone = preg_replace( '/\D/', '', $order->get_billing_phone() ); // digits only, incl. country code
$user_data['ph'] = array( hash( 'sha256', $phone ) );
}
// fbp / fbc come from cookies set on landing. NEVER hash them.
if ( ! empty( $_COOKIE['_fbp'] ) ) {
$user_data['fbp'] = sanitize_text_field( wp_unslash( $_COOKIE['_fbp'] ) );
}
if ( ! empty( $_COOKIE['_fbc'] ) ) {
$user_data['fbc'] = sanitize_text_field( wp_unslash( $_COOKIE['_fbc'] ) );
}
$user_data['client_ip_address'] = $order->get_customer_ip_address();
$user_data['client_user_agent'] = $order->get_customer_user_agent();
// ---- custom_data ----
$custom_data = array(
'currency' => $order->get_currency(),
'value' => (float) $order->get_total(),
'order_id' => (string) $order->get_id(),
);
// ---- the event ----
$payload = array(
'data' => array(
array(
'event_name' => 'Purchase', // MUST match the Pixel event name exactly
'event_time' => time(),
'event_id' => $event_id, // MUST match the Pixel eventID exactly
'action_source' => 'website',
'event_source_url' => $order->get_checkout_order_received_url(),
'user_data' => $user_data,
'custom_data' => $custom_data,
),
),
);
$url = "https://graph.facebook.com/{$api_version}/{$dataset_id}/events?access_token={$access_token}";
$response = wp_remote_post( $url, array(
'headers' => array( 'Content-Type' => 'application/json' ),
'body' => wp_json_encode( $payload ),
'timeout' => 10,
) );
if ( is_wp_error( $response ) ) {
error_log( 'D-Office CAPI error: ' . $response->get_error_message() );
return;
}
if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
$order->update_meta_data( '_doffice_capi_sent', 1 );
$order->save();
} else {
error_log( 'D-Office CAPI response: ' . wp_remote_retrieve_body( $response ) );
}
}woocommerce_thankyou הוא פתרון מצוין ללמידה, אבל בחנות אמיתית עדיף לשלוח את האירוע מנקודת אישור התשלום (Webhook של שער הסליקה או שינוי Order Status), כדי לא להיות תלויים בכך שהלקוח יחזור לעמוד התודה. לקוח שסוגר את הדפדפן מיד אחרי התשלום לא תמיד יגיע לשם, ואירוע הדפדפן יאבד, וזו בדיוק ההמרה היקרה ביותר. כך זה נעשה בחנויות גדולות: האירוע מחובר לאישור התשלום עצמו, לא לעמוד התודה.ב-Events Manager פותחים את Test Events, ומוסיפים זמנית את קוד הבדיקה ל-payload של השרת:
// While testing: add your Test Events code to the payload, // then watch Events Manager -> Test Events in real time. $payload['test_event_code'] = 'TESTXXXXX'; // A correctly deduplicated Purchase appears ONCE, // marked as received from two sources: Browser and Server.
מבצעים רכישת בדיקה. אם הכל תקין, הרכישה מופיעה פעם אחת, מסומנת כמתקבלת משני מקורות: Browser ו-Server. אם היא מופיעה פעמיים, ה-event_id או ה-event_name לא זהים בין הערוצים.
$api_version.אותו דפוס בדיוק עובד לכל אירועי המסחר, עם ה-event_id הייעודי של כל אחד:
ל-begin_checkout שולחים InitiateCheckout עם ה-event_id מבוסס-העגלה, ול-add_to_cart שולחים AddToCart, כל אחד עם ה-event_id שלו.
איפה אנחנו עכשיו: בנינו את שכבת המדידה למסחר אלקטרוני, מקצה לקצה. האירועים נשלחים ל-GA4, נשלחים גם ל-Meta, ומדווחים פעם אחת בלבד. הצעד המשלים הוא Enhanced Conversions ל-Google Ads, שיסגור את אותו מעגל מול גוגל בדיוק כמו מול Meta. מכאן ואילך העבודה היא בשיפור איכות הנתונים (EMQ, Consent Mode, ומדידה בצד השרת עם Server GTM), לא בהוספת אירועים נוספים.
נחבר לכם את הפיקסל וה-CAPI עם דדופליקציה נכונה, נחזק את איכות ההתאמה (EMQ), ונוודא שכל המרה נספרת פעם אחת, בדפדפן ובשרת גם יחד.
בואו נדבר