Description
Netro Ads installs the Meta Pixel, the Meta Conversions API, Google Ads conversion tracking, Google Analytics 4, Google Tag Manager and the ChatGPT Ads (OpenAI) Measurement Pixel and Conversions API from one settings screen and measures the conversions that matter on a service business site: phone calls, WhatsApp messages, form submissions and (optionally) WooCommerce purchases.
It is server-side tracking without a tag server: every conversion is sent from the browser and from your WordPress server (Meta CAPI and OpenAI Conversions API), so an ad blocker or an event name Meta restricts in the browser does not cost you the conversion. Call tracking and WhatsApp click tracking work on any theme, and the consent gate (GDPR, Google Consent Mode v2) is on by default.
The browser event and the server event share a single event ID, so each platform de-duplicates them and counts one conversion instead of two. One user action gets one ID, used for every platform.
Google Ads, Google Analytics 4 and Google Tag Manager
Paste a GA4 measurement ID (G-…), a Tag Manager container (GTM-…) and a Google Ads conversion ID (AW-…) — or the whole snippet Google gives you; the IDs are read out of it. The same actions are then reported to Google:
- Google Ads conversions for form submissions, phone clicks, WhatsApp clicks and other contact links (email, Messenger, Telegram), each with its own conversion label or one shared contact label. A missing label is reported in the status list: Google ignores a conversion without one and shows no error.
- GA4 events:
page_view,generate_lead,contact(with the method: phone, WhatsApp, email…) and, with WooCommerce,purchasewith value, currency and transaction ID. - With WooCommerce, purchases go to Google Ads under their own conversion label, with value, currency and the order number as
transaction_id. - Tag Manager
dataLayerevents you can trigger your own tags on:netroads_contact,netroads_lead,netroads_purchase. - Google Consent Mode v2 defaults are set before any Google tag loads and updated when the visitor decides.
Google events are sent from the browser; the server-side channel covers Meta and OpenAI.
ChatGPT Ads (OpenAI)
Paste the Pixel ID and a Conversions API key from ChatGPT Ads Manager and the same actions are measured there too: page views, contact clicks and form submissions (lead_created by default), and with WooCommerce contents_viewed, items_added, checkout_started and order_created. OpenAI’s own rules are applied, which differ from Meta’s: names are normalised without spaces before hashing, amounts are sent as integers in the currency’s minor unit (three decimals for KWD, none for JPY), and the oppref click identifier is carried from the landing page to later server events.
What it measures without any setup per page
- PageView on every page.
- Contact on every phone, WhatsApp, Messenger, Telegram, SMS or email link — in any theme or page builder, including links added later or inserted by a page builder. One delegated listener covers the whole site; you never mark a link.
- Lead after a form submission actually succeeds: Contact Form 7, WPForms, Gravity Forms, Elementor Pro Forms, Fluent Forms. A failed or invalid submission produces nothing.
- ViewContent on the post types you choose.
- AddToCart, InitiateCheckout and Purchase when WooCommerce is active. Purchase is sent once per order even if the thank-you page is refreshed.
- Anything else: add
data-netroads-conversion="lead"(or"contact") to a button or form.
Built for the things that fail silently
Every failure mode of pixel measurement is silent — nothing errors, conversions just stop arriving. The status panel on the settings screen names each one:
- Meta restricts certain event names on individual pixels (common on health and aesthetics accounts). The browser drops such an event with no error at all. The plugin reads your pixel’s own configuration, tells you when your contact event is restricted, and lets you pick another name — used on both channels so de-duplication still works.
- The event ID is generated in the browser, never printed into HTML, so a full page cache cannot hand one ID to every visitor.
fbclidis captured on the landing page and carried through the session, so events from inner pages still carry the click ID.- Phone numbers are normalised with a country code on both channels from one shared rule; a mismatch between browser and server hashing zeroes matching without any error.
fbp,fbc, IP and user agent are never hashed; email and phone are hashed on the server and passed in plain text to the pixel, which hashes them itself.- Contact clicks leave the page immediately, so server events are sent with
navigator.sendBeaconand survive the unload. - A filled-in test event code sends your live conversions to the Test Events stream instead of your dataset. The panel flags it in red.
- The access token is stored outside the settings array, is never printed on the front end, and can live in
wp-config.phpinstead of the database.
Privacy
Nothing is sent to the plugin author. This plugin has no servers of its own,
no analytics of its own, no licence check and no usage reporting. The only
destinations it ever contacts are the advertising accounts the site owner
configures: Meta (Facebook), OpenAI (ChatGPT Ads) and Google — each only if the
site owner enters an ID for it.
The consent gate is on by default. On a fresh install the consent mode is
“strict”: no measurement script is loaded and no event is sent until the visitor
agrees. A built-in banner asks, unless one of the supported consent plugins is
detected, in which case that plugin’s decision is used. Turning the gate off is
an explicit choice the site owner has to make in the settings, and the settings
screen says what that means.
The visitor’s browser decides, not the server. The consent state is read in
the browser, so a cached page cannot serve one visitor’s decision to another.
The admin area is never measured. No event is sent from wp-admin, and by
default logged-in administrators, editors and shop managers are not measured on
the front end either.
What leaves the site, once configured and consented to: the event name, the
page URL, the visitor’s IP address and user agent, Meta’s own _fbp / _fbc
cookies, and — for form and order conversions — the email address, phone number,
name, city, postcode and country the visitor typed, SHA-256 hashed before they
leave the server. The site owner is the data controller for all of it.
External services
This plugin sends data to Meta (Facebook) and, if you configure them, to OpenAI and Google. Nothing is sent before you enter an ID.
Meta Conversions API (graph.facebook.com) — when you save a dataset ID and an access token, conversion events are sent from your server: event name, event time, page URL, the visitor’s IP address and user agent, the _fbp / _fbc cookies, and — for form and order conversions — the email address, phone number, name, city, postcode and country hashed with SHA-256 before they leave your site. Terms: https://www.facebook.com/legal/terms/businesstools — Privacy: https://www.facebook.com/privacy/policy
Meta Pixel (connect.facebook.net) — the pixel script is loaded in the visitor’s browser and reports the same events. Terms and privacy as above.
Meta pixel configuration (connect.facebook.net/signals/config/<id>) — read once every 12 hours in the admin area to detect event names Meta restricts on your pixel. No visitor data is sent.
The plugin also reads the site’s own home page once every six hours from the
admin area, to detect measurement tags installed by the theme or another plugin.
That request stays on the site’s own domain.
OpenAI Measurement Pixel (bzrcdn.openai.com, bzr.openai.com) — loaded in the visitor’s browser only if an OpenAI Pixel ID is saved, and only after marketing consent. It reports the same events and handles OpenAI’s own click identifier. Terms: https://openai.com/policies/advertising-terms/ — Privacy: https://openai.com/policies/
OpenAI Conversions API (bzr.openai.com/v1/events) — when an OpenAI Pixel ID and Conversions API key are saved, conversion events are sent from your server: event name, event time, page URL, the visitor’s IP address and user agent, OpenAI’s oppref and obref identifiers, and — for form and order conversions — the email address, phone number and name hashed with SHA-256, plus city, region, postcode and country as plain text, as OpenAI’s documentation specifies. The “Test server connection” button sends one event with validate_only, which OpenAI checks but does not save. Documentation: https://developers.openai.com/ads/conversions-api
Google (googletagmanager.com, google-analytics.com, googleadservices.com) — loaded in the visitor’s browser only if you enter a GA4, Google Tag Manager or Google Ads ID, and in the default strict consent mode only after the visitor agrees. In the optional Consent Mode v2 “advanced” setting they load before consent without writing cookies. It reports the page view and the conversions listed above; no data is sent from your server. Terms: https://policies.google.com/terms — Privacy: https://policies.google.com/privacy
Screenshots






Installation
- Install and activate the plugin.
- Open Netro Ads in the admin menu.
- Paste your dataset (pixel) ID — the whole snippet from Events Manager also works.
- Paste a Conversions API access token (Events Manager Settings Conversions API). Without it only the browser measures.
- Enter your business phone number with its country code, so visitor phone numbers can be normalised the way Meta expects.
- Optional: on the Google tab, paste your GA4, Tag Manager and Google Ads IDs and the conversion labels.
- Check the status list: it tells you what is missing and what that stops.
FAQ
-
Do I have to paste code into my theme?
-
No. Nothing is added to your theme, and no code is copied from the Meta or Google panels — paste the IDs (or the whole snippet) into this screen instead.
-
Does it work with a caching plugin?
-
Yes, and it is built for it: no per-visitor value is ever printed into the HTML, so cached pages stay correct. Measured with a full page cache serving byte-identical HTML to two visitors: the event IDs differ.
-
Is consent supported?
-
Yes, and it is on by default: a new install starts in “strict” mode, where no measurement script loads until the visitor agrees. Complianz, CookieYes, Borlabs Cookie and Real Cookie Banner are detected and their decision is used; otherwise a simple built-in banner asks. Google Consent Mode v2 defaults are set before any Google tag loads. Meta has no cookieless mode, so the pixel is never loaded before marketing consent. You can switch the gate off if your audience is outside the EU/UK, but that is a deliberate choice, not the default.
-
Does it support ads in ChatGPT?
-
Yes. The OpenAI tab takes the Pixel ID and the Conversions API key from ChatGPT Ads Manager (Tools Conversions). Contact clicks and form submissions are sent as
lead_createdby default — OpenAI has no separate contact event, and its documentation defineslead_createdas a lead form or a contact request. You can report contact clicks as a customcontactevent instead. Whatever you pick, create the same event in Ads Manager and attach it to your campaign. -
Where does the access token live?
-
In its own option, never in the settings array and never in front-end output. For a stricter setup, define
NETROADS_CAPI_TOKENinwp-config.phpand the field is ignored. -
My conversions do not arrive and there is no error.
-
Open the status list. The usual causes are a missing access token, a test event code left in place, a Google Ads conversion label left empty, an event name Meta restricts on your pixel, or a REST API blocked by a security plugin — each one is reported there by name.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“Netro Ads – Pixel & Conversions API for Meta, Google Ads and ChatGPT” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “Netro Ads – Pixel & Conversions API for Meta, Google Ads and ChatGPT” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.1.3
- Fix: WooCommerce purchases were reported to Google Ads under the form (lead)
conversion label. Purchases now have their own “WooCommerce purchase label”
on the Google tab, carry the order number astransaction_idso Google
de-duplicates them, and are never sent under a form or contact label. The
status list says when the label is missing. - Fix: on a store with only Google (GA4 / Google Ads) configured, the purchase
was never sent, and the thank-you page could report it again on reload. - Fix: when the visitor accepts cookies on the thank-you page itself, the
purchase is now sent after the Google tags are configured, not before. - The admin menu shows the Netrobit logo; plugin name and description now
mention Google Ads, GA4 and Tag Manager.
1.1.2
- Security: the WooCommerce Purchase payload is now printed from the
woocommerce_thankyou hook, which WooCommerce fires only after its own
order-key, account and email checks. The plugin no longer reads the order ID
from the request and never prints the order key. - Inline JSON is encoded with JSON_HEX_TAG and related flags.
- The “Saved” notice no longer relies on a query argument.
1.1.1
- OpenAI events are sent only to this plugin’s own Pixel ID (
measureSingle).
Withmeasure, every event also reached any other OpenAI pixel already on
the page — for example one pasted into the theme by hand. - OpenAI server requests wait up to 10 seconds and are retried once on a
network error, with the same event ID so OpenAI de-duplicates the retry. - A network delay is now reported as a warning, not as a broken setup, and is
re-checked after a minute.
1.1.0
- New: ChatGPT Ads (OpenAI) Measurement Pixel and Conversions API. Same actions,
same consent gate, same event ID as Meta; OpenAI’s own normalisation and
minor-unit amounts;opprefcarried from the landing page. - The “Test server connection” button now tests every configured platform.
- The status list reports OpenAI setup and any other OpenAI pixel already on
the page.
1.0.4
- The consent gate is now on by default: a new install starts in strict mode and
loads nothing until the visitor agrees. - The public reachability endpoint no longer reports whether an access token is
configured; that answer now comes only from the administrator-only route. - Removed a plugin header URL that did not resolve.
1.0.3
- New check: the plugin reads your own home page once (cached for six hours) and
reports measurement tags that are not its own — a second Meta pixel, Google
tags already loaded by the theme or another plugin, or a duplicate domain
verification tag. Each of those makes conversions count twice or verification
fail, and none of them produces an error anywhere. - The domain verification field now warns when the value looks like a numeric ID
rather than a verification code.
1.0.2
- The event name a successful form submission sends is now a setting, like the
contact click name already was. Both channels always use the same name. - The restriction check now compares every event name the site actually sends
against the pixel’s own restriction list, and says what it means for you: with
a working server side a restricted name is a warning (the conversion still
arrives), without one it is a failure (the conversion is lost). - Fixed a stale diagnostic: the endpoint reachability result was cached for an
hour, so a check that ran before the plugin was configured kept reporting a
409 long after the settings were saved. Saving now clears every diagnostic
cache, failures are cached for five minutes, and the check no longer runs at
all while the plugin is unconfigured.
1.0.1
- The “Test server connection” button now checks whether the token can actually
send events, instead of reading the dataset’s name. A Conversions API token
can send events without being allowed to read the dataset object, so a
working setup was reported as “(#100) Missing Permission”. - The status panel reports the same check, and each authentication failure now
names its own cause: expired token, dataset not assigned to the token’s user,
or an ID that belongs to another business.
1.0.0
- First release.
