Title: Pixel Made Simple
Author: Dominik Seitz
Published: <strong>September 19, 2026</strong>
Last modified: September 19, 2026

---

Search plugins

![](https://ps.w.org/pixel-made-simple/assets/banner-772x250.png?rev=3703113)

![](https://ps.w.org/pixel-made-simple/assets/icon.svg?rev=3703113)

# Pixel Made Simple

 By [Dominik Seitz](https://profiles.wordpress.org/seitzdominik/)

[Download](https://downloads.wordpress.org/plugin/pixel-made-simple.0.12.7.zip)

 * [Details](https://wordpress.org/plugins/pixel-made-simple/#description)
 * [Reviews](https://wordpress.org/plugins/pixel-made-simple/#reviews)
 *  [Installation](https://wordpress.org/plugins/pixel-made-simple/#installation)
 * [Development](https://wordpress.org/plugins/pixel-made-simple/#developers)

 [Support](https://wordpress.org/support/plugin/pixel-made-simple/)

## Description

Pixel Made Simple is a deliberately minimal tracking plugin. No jQuery, no frameworks,
no DOM listeners in the frontend – just the official platform loaders (loaded asynchronously)
plus a few lines of inline code.

**What the plugin does**

 * **Meta Pixel + Conversions API (CAPI):** Browser pixel and server-side events
   from the same WordPress request. Every event gets one UUID that is passed to 
   both `fbq()` (`eventID`) and the Conversions API (`event_id`), so Meta deduplicates
   the pair automatically.
 * **Fire-and-forget CAPI:** Server-side events are sent non-blocking via `wp_remote_post()`–
   no impact on page load time. `user_data` contains client IP, user agent, the `
   _fbp`/`_fbc` cookies (with a fallback from `fbclid`) and – optionally – the SHA-
   256 hashed email address of logged-in users.
 * **Google Ads (gtag.js):** Conversion tracking with your Google Tag, including
   Google Consent Mode v2 defaults – `ad_storage`, `ad_user_data`, `ad_personalization`
   and `analytics_storage` start out as “denied” and your banner sends the update.
   Form leads additionally carry Enhanced Conversions data, hashed to Google’s own
   rules (they differ from Meta’s, so both values are carried separately).
 * **Google Analytics 4:** Reuses the same `gtag.js` loader – enter the Measurement
   ID and page views and events are picked up. Independent of Google Ads above.
 * **TikTok Pixel:** The official web events, fired with the same event ID as the
   matching Meta event.
 * **URL-based events:** Define any number of URL rules (“exact path” or “URL contains”)
   that fire a standard or custom event on Meta, Google Ads and TikTok at once, 
   e.g. `Lead` on `/thank-you/`. Ideal for thank-you and confirmation pages.
 * **Handover to the confirmation page:** A confirmation page does not know the 
   email address, so on its own it can only pass on IP and user agent – and Meta
   barely uses such a server event for attribution. With form lead tracking enabled,
   the submission hands its event ID and its hashed contact data to the next page
   through the browser’s `sessionStorage`. A matching URL rule there reports the
   _same_ event instead of a second one: if the submission got through, Meta deduplicates
   the pair; if it was lost during the redirect, the confirmation page is its full
   replacement. Either way one conversion – with email and phone in the match. With
   Google Ads configured, the same conversion also carries Enhanced Conversions 
   data (`gtag('set','user_data', …)`), hashed to Google’s own rules – they differ
   from Meta’s, so both values are carried separately.
 * **Automatic form lead tracking (off by default):** Detects submissions of Contact
   Form 7, Elementor Pro, Fluent Forms, WPForms, Gravity Forms, SureForms and plain
   HTML forms and fires `Lead` or `Contact` in the browser and via CAPI with the
   same event ID. Email and phone number are hashed with SHA-256 before they leave
   your server; raw values are never stored or logged. Optional URL filter and automatic
   exclusion of search, comment and login forms. Submissions that redirect to a 
   confirmation page hand their data over to it (see above).
 * **GDPR cookie banner detection (on by default):** Recognises Must Have Plugins
   Cookie Bar, Borlabs Cookie, Complianz, Real Cookie Banner, CookieYes, Cookiebot,
   SureCookies and any banner that implements the WP Consent API, and holds back
   browser and server events until the visitor grants marketing consent. Tracking
   starts right after the click on “Accept” – no reload. Sites without a cookie 
   banner are never blocked. A consent mode lets you choose whether server-side 
   events wait for the banner as well (recommended) or only the browser pixel does.
 * **Cookieless analytics (Plausible, Umami, Rybbit):** Load the base script of 
   a privacy-friendly analytics provider straight from the _Privacy Trackers_ tab–
   two fields per provider, the script URL from your dashboard and the site identifier.
   Deliberately limited to the base script: no custom events, no goals, no server-
   side connection. Each provider has its own _Load without consent_ switch (off
   by default); when it is off the tracker waits for consent exactly like the advertising
   pixels, and when it is on it loads immediately – for that one provider only, 
   while Meta, Google and TikTok stay blocked. Nothing at all is written to your
   page source until a provider is switched on and both of its fields are filled.
 * **Event log:** A small table in your WordPress admin lists the most recent browser
   and server-side events (event name, event ID, platform, status, match keys) so
   you can verify your setup without leaving WordPress. Filter by status, event 
   name or platform; entries are deleted automatically after 3, 7, 14 or 30 days,
   whichever you choose.
 * **Live debug bar for administrators:** A discreet bar at the bottom of the frontend
   shows consent status (including the detected banner), fired events, event IDs,
   the CAPI response and the match keys used. Rendered exclusively for logged-in
   administrators – regular visitors get zero additional bytes.
 * **Test event code with auto-expiry:** The Meta test event code is removed automatically
   after 12 hours, so no test traffic ends up in your live reports by accident.
 * **Privacy by default:** Form lead tracking is disabled on new installations, 
   the CAPI access token is only ever used server-side and never rendered in the
   frontend, and the event log stores field _names_ only – never values or hashes.
 * **Consent statistics:** One card above the event log answers a single question–
   how much of your tracking is the cookie banner eating? Aggregated daily counters
   only, for 7 or 30 days, with a daily breakdown and a CSV export.
 * **Export & import:** Download the whole configuration as JSON and apply it on
   another site in one step.
 * **Translation-ready:** English source strings and a POT template are included;
   German and other locales come from translate.wordpress.org.

**Pixel Made Simple Pro**

Everything described above is included here, without limits or license checks. [Pixel Made Simple Pro](https://pixelmadesimple.com)
is a separate plugin for online shops and campaign attribution. It adds WooCommerce
and SureCart tracking (ViewContent, AddToCart, InitiateCheckout and Purchase for
all four platforms, with a server-side Purchase fallback and optional advanced matching),
the TikTok Events API for server-side purchase events, and first-touch/UTM attribution
with automatic form fill. Both plugins use the same option keys, so switching between
them keeps your configuration.

### External services

This plugin connects to third-party tracking services. Nothing is sent until you
enter the respective ID/token and switch the platform on. With cookie banner detection
enabled, nothing is sent before the visitor has granted marketing consent either–
the one exception is a privacy tracker whose _Load without consent_ switch you have
turned on yourself, and that exception applies to that provider alone.

**Meta (Facebook) – Meta Pixel and Conversions API**

 * The browser loads the official pixel script from `https://connect.facebook.net/`
   and sends events to `https://www.facebook.com/tr` (including the `<noscript>`
   fallback image). This happens on every page view for which tracking is active.
 * The Conversions API request goes from your server to `https://graph.facebook.
   com/` whenever a URL event matches or a tracked form is submitted (for a URL 
   event that takes part in the handover to the confirmation page, the browser asks
   your server to send it). It contains the event name, time, event ID, page URL,
   the visitor’s IP address and user agent, the `_fbp`/`_fbc` cookie values if present
   and – only where enabled – SHA-256 hashes of the email address/phone number (
   form leads, logged-in users) or of billing details (Pro e-commerce tracking).
 * Terms of service: https://www.facebook.com/legal/terms – Privacy policy: https://
   www.facebook.com/privacy/policy/ – Platform terms: https://developers.facebook.
   com/terms/

**Google – Google Ads and Google Analytics 4**

 * The browser loads `gtag.js` from `https://www.googletagmanager.com/` and sends
   page views, conversions and e-commerce events to Google Ads / Google Analytics.
   For form leads the conversion additionally carries SHA-256 hashes of the email
   address and – where an international number is available – the phone number (
   Enhanced Conversions). For purchases with advanced matching enabled it carries
   the same two plus hashed first and last name, and city, region, postal code and
   country in the clear. There is no server-side connection to Google. With Consent
   Mode v2 enabled, all consent signals default to “denied” until your banner updates
   them. There is no server-side connection to Google.
 * Terms: https://policies.google.com/terms – Privacy: https://policies.google.com/
   privacy – Google Analytics terms: https://marketingplatform.google.com/about/
   analytics/terms/us/

**TikTok – TikTok Pixel and Events API** (the Events API is part of Pixel Made Simple
Pro)

 * The browser loads the pixel from `https://analytics.tiktok.com/` and sends web
   events to TikTok. For purchases the server additionally sends an Events API request
   to `https://business-api.tiktok.com/` containing the event, event ID, IP address,
   user agent, order values and – only where enabled – the hashed email address 
   and, where an international number is available, the hashed phone number.
 * Terms: https://www.tiktok.com/legal/page/global/terms-of-service/en – Privacy:
   https://www.tiktok.com/legal/page/row/privacy-policy/en – Business products terms:
   https://ads.tiktok.com/i18n/official/policy/business-products-terms

**Plausible, Umami and Rybbit – cookieless analytics** (all off by default)

 * Unlike the platforms above, the address contacted here is **not part of the plugin**.
   You paste the script URL from your own dashboard into the _Privacy Trackers_ 
   tab; the plugin ships no default and never assembles one from a host name. Which
   server receives the data therefore depends on your account – the provider’s cloud
   for a hosted plan, your own machine for a self-hosted instance. The example addresses
   shown in the empty fields are placeholders, never sent.
 * Nothing is loaded for a provider until you switch it on **and** fill in both 
   of its fields. Until then not a single line for it appears in your page source.
 * **Plausible:** the browser loads the script from the address you entered (typically`
   https://plausible.io/js/script.js`) and reports a page view for every page on
   which tracking is active, tagged with the domain you entered. Service: https://
   plausible.io/ – Terms: https://plausible.io/terms – Privacy: https://plausible.
   io/privacy – What Plausible collects: https://plausible.io/data-policy
 * **Umami:** same, from the address you entered (typically `https://cloud.umami.
   is/script.js`), tagged with the website ID you entered. Service: https://umami.
   is/ – Terms: https://umami.is/terms – Privacy: https://umami.is/privacy
 * **Rybbit:** same, from the address you entered (typically `https://app.rybbit.
   io/api/script.js`), with the site ID appended to the URL as `?siteId=`. Service:
   https://www.rybbit.io/ – Terms: https://www.rybbit.io/terms-and-conditions – 
   Privacy: https://www.rybbit.io/privacy
 * The plugin loads each provider’s **base script and nothing else**: no custom 
   events, no goals, no e-commerce data, and no server-side connection of any kind.
   What that script then collects is the provider’s business and is described in
   their own documentation above.
 * Consent: by default each provider waits for marketing consent exactly like the
   advertising pixels, and starts without a page reload once the visitor accepts.
   The per-provider _Load without consent_ switch changes that for **that one provider
   only** – Meta, Google and TikTok stay blocked either way.

**SureCart – licensing and automatic updates** (Pro only)

 * The Pro version activates its license and checks for updates against `https://
   api.surecart.com`. This happens when you activate or deactivate a license on 
   the “License” page, and when WordPress checks for plugin updates (the result 
   is cached for three hours). Transmitted are the license key you entered, your
   site URL and your site title.
 * The free version never contacts this service. It is updated through WordPress.
   org and contains no update checker of its own.
 * Terms: https://surecart.com/terms-and-conditions/ – Privacy: https://surecart.
   com/privacy-policy/

A freshly activated Pixel Made Simple contacts nothing at all: with no platform 
configured, the plugin writes no third-party script, image or request into your 
pages. Every connection described above needs a setting you made yourself. The settings
pages link to https://pixelmadesimple.com (documentation, tutorials, Pro upgrade).
These are plain links – no data is transmitted unless you click them. The free version
contains no update checker or telemetry of its own; updates come from WordPress.
org.

### Privacy

 * Personal data is only ever sent to the platforms above, never stored by the plugin.
   Email addresses and phone numbers from form submissions are hashed (SHA-256) 
   in memory and discarded.
 * The event log stores event names, event IDs, status codes and the _names_ of 
   the match keys used (e.g. `em, fbc`) – never the values.
 * The consent statistics store **aggregated daily counters only**: one row per 
   calendar day with three integers (sent, blocked by consent, not configured). 
   There is no IP address, no user agent, no event ID and no timestamp below day
   level – the plugin does not and cannot track _who_ declined consent. Rows older
   than 30 days are deleted automatically.
 * The handover to the confirmation page uses the browser’s `sessionStorage` and
   holds an event ID plus SHA-256 hashes – four of them since 0.11.1 (Meta and Google
   normalise differently), never a plain-text email address or phone number. The
   entry is never sent to the server, does not survive closing the tab, expires 
   after 10 minutes and can be used exactly once. In the default consent mode it
   is not created at all without marketing consent.
 * The first-touch attribution cookie `pxms_attribution` (Pro, off by default) stores
   UTM parameters and click IDs for 30 days in a first-party cookie.
 * Please check with your data protection officer whether the “Block browser pixels
   only” consent mode is permissible for your site; the default (“Fully GDPR compliant”)
   blocks server-side events as well.

## Screenshots

[⌊General tab – Meta Pixel and the Conversions API access token.⌉⌊General tab – 
Meta Pixel and the Conversions API access token.⌉[

General tab – Meta Pixel and the Conversions API access token.

[⌊General tab – GDPR cookie banner detection with the detected banner and the consent
mode.⌉⌊General tab – GDPR cookie banner detection with the detected banner and the
consent mode.⌉[

General tab – GDPR cookie banner detection with the detected banner and the consent
mode.

[⌊Live debug bar for administrators in the frontend.⌉⌊Live debug bar for administrators
in the frontend.⌉[

Live debug bar for administrators in the frontend.

[⌊Event Log – recent browser and CAPI events with status and match keys.⌉⌊Event 
Log – recent browser and CAPI events with status and match keys.⌉[

Event Log – recent browser and CAPI events with status and match keys.

[⌊Privacy Trackers tab – Plausible, Umami and Rybbit, each with its own Load without
consent switch.⌉⌊Privacy Trackers tab – Plausible, Umami and Rybbit, each with its
own Load without consent switch.⌉[

Privacy Trackers tab – Plausible, Umami and Rybbit, each with its own _Load without
consent_ switch.

[⌊Advanced Tracking tab – automatic form lead tracking.⌉⌊Advanced Tracking tab –
automatic form lead tracking.⌉[

Advanced Tracking tab – automatic form lead tracking.

[⌊URL Events tab – URL rules with per-event platform assignment.⌉⌊URL Events tab–
URL rules with per-event platform assignment.⌉[

URL Events tab – URL rules with per-event platform assignment.

## Installation

 1. Upload the plugin via _Plugins  Add New  Upload Plugin_ and activate it, or install
    it from the WordPress.org plugin directory.
 2. Open _Pixel Made Simple_ in the admin menu, expand _Meta (Facebook)_, enter your
    Pixel ID and switch the platform on.
 3. Optional: paste your Conversions API access token (Meta Events Manager  Data sources
    Settings  Conversions API) – the Conversions API switches on automatically.
 4. In the _URL Events_ tab, add rules for your thank-you or confirmation pages. For
    forms without a redirect, enable _Automatic form lead tracking_ in the _Advanced
    Tracking_ tab instead.
 5. Check the _Event Log_ and the live debug bar (visible to administrators in the 
    frontend) to verify that events arrive.

## FAQ

### Which services does the plugin contact?

Only the ones you configure yourself. With no platform set up it writes no third-
party script, image or request into your pages at all. Every address it can contact,
what is transmitted and when, is listed under _External services_ below.

### How do I test the Meta server events?

Enter the test event code from the Events Manager (tab _Test events_) in the _General_
tab. Server events then show up there in real time. The code is removed automatically
after 12 hours. For debugging you can make the request blocking, after which the
raw Meta response is written to the debug log when `WP_DEBUG_LOG` is enabled:

    ```
    add_filter( 'pxms_capi_blocking', '__return_true' );
    ```

### Do the privacy trackers need a cookie banner consent?

That is your decision, and the plugin lets you make it per provider. By default 
every privacy tracker runs through exactly the same marketing consent gate as the
Meta, Google and TikTok pixels – nothing loads until the visitor accepts, and it
then starts without a page reload. The _Load without consent_ switch changes that
for one provider only; the advertising platforms are never affected by it.

The background: Section 25 TDDDG covers storing information on, or reading it from,
a visitor’s device. A tracker that sets no cookie and uses no local storage is not
covered by it; the GDPR level applies regardless. Whether that reasoning holds depends
on the specific service and where it is hosted, and it is legally contested. Pixel
Made Simple makes no claim about any third-party service being compliant – it only
provides the setting.

### Which script URL do I enter for Plausible, Umami or Rybbit?

The one from your own dashboard, copied verbatim – for example `https://plausible.
io/js/script.js`, `https://cloud.umami.is/script.js` or `https://app.rybbit.io/api/
script.js`. Self-hosted instances use your own domain instead.

The plugin deliberately does not assemble that address from a host name. All three
providers have changed their paths at least once (Umami moved from `/umami.js` to`/
script.js`, Plausible issues newer accounts a per-site tracker filename, Rybbit 
switched from an attribute to a query parameter). A path guessed by the plugin would
eventually be silently wrong: the script loads and no data arrives.

### Do the privacy trackers show up in the event log or the consent statistics?

No, and that is intentional. They are not conversions, they never go through the
Conversions API, and counting them would dilute exactly the numbers you use to investigate
missing advertising conversions. The event log and the consent statistics keep reporting
on Meta, Google and TikTok only.

### How does the plugin work with my cookie banner?

The automatic cookie banner detection (on by default) checks the consent cookies
of the supported banner plugins and the WP Consent API on the server. Without marketing
consent the browser scripts are deferred (they listen for the banner’s consent events
and start right after the click on “Accept”) and the Conversions API request is 
not sent. If no supported banner is installed, nothing is blocked.

For unsupported banners you can provide the consent result yourself:

    ```
    add_filter( 'pxms_has_marketing_consent', function ( $consent ) { return my_marketing_consent(); } );
    ```

And you can suppress all tracking server-side:

    ```
    add_filter( 'pxms_allow_tracking', function ( $allow ) { return my_consent_check(); } );
    ```

### Does the plugin work with page caching?

The browser pixel: yes. The Conversions API is normally only triggered when PHP 
actually renders the page, so with aggressive full-page caching you should exclude
your conversion pages from the cache – otherwise CAPI events are not sent at all,
and every visitor shares the one event ID baked into the cached HTML.

One exception, since 0.11.0: a URL event that participates in the handover to the
confirmation page is sent from the browser and generates its event ID per visitor.
That one works on a cached page. All other URL events still need the page to be 
excluded from the cache.

### My thank-you page is on a different domain. Does the handover still work?

No. `sessionStorage` belongs to exactly one origin, so nothing travels to another
domain or subdomain – the same applies to a form inside an iframe from a different
origin. In those cases both events are counted separately, exactly as before version
0.11.0. If the confirmation page is on a subdomain, moving it to a path on the main
domain (`/thank-you/` instead of `thanks.example.com`) is enough to get the full
match.

### Google Ads shows no enhanced conversions data. What is missing?

Three things have to line up. In your Google Ads account, Enhanced Conversions must
be enabled for that conversion action and the customer data terms accepted – without
that Google discards the data silently and still counts the conversion. In the plugin,
the event needs a conversion label. And for the phone number Google requires the
international format: if your form collects `0151 …` without a country code, only
the email address is sent. The filter `pxms_normalize_phone` can add the country
code.

### Which filters are available?

 * `pxms_allow_tracking` – allow or suppress tracking globally.
 * `pxms_has_marketing_consent` – override the result of the cookie banner detection(
   guards the browser pixel).
 * `pxms_has_server_consent` – the same for server-side signals (Conversions API,
   TikTok Events API). Only relevant when the consent mode is set to “Block browser
   pixels only”.
 * `pxms_consent_banner_active` – register your own banner with the detection.
 * `pxms_consent_events` – additional banner events for the frontend listener.
 * `pxms_capi_event_data` – modify a single CAPI event before it is sent (e.g. add`
   custom_data`).
 * `pxms_capi_user_data` – modify the `user_data` payload.
 * `pxms_normalize_phone` – adjust the normalised phone number before hashing (e.
   g. add a country code). Also decides whether Google gets a phone number at all:
   without a country code there is no valid E.164 value, and none is sent.
 * `pxms_graph_api_version` – override the Graph API version.
 * `pxms_capi_blocking` – send the CAPI request blocking (debugging).
 * `pxms_tiktok_capi_blocking` – the same for TikTok Events API requests (Pixel 
   Made Simple Pro, debugging).

Upgrading from “Lightweight Meta Pixel & CAPI Tracker”? These filters used to be
called `lmpct_*`. Custom code that hooks into one of them must be updated to the`
pxms_*` names – see the 0.6.0 changelog entry.

### How do I translate the plugin?

Source strings are English. The `/languages` folder contains the POT template and
the finished German translation (`-de_DE.po`/`.mo`). Custom translations made with
Loco Translate are best stored under “System” (`wp-content/languages/loco/plugins/`)
so they survive updates.

### Is all data removed on uninstall?

Yes, as soon as neither variant (free or Pro) is installed anymore. `uninstall.php`
then deletes all plugin options including the stored access token, the event log
table and the scheduled cleanup task. Switching from free to Pro (or back) keeps
your configuration – both use the same option keys.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“Pixel Made Simple” is open source software. The following people have contributed
to this plugin.

Contributors

 *   [ Dominik Seitz ](https://profiles.wordpress.org/seitzdominik/)

[Translate “Pixel Made Simple” into your language.](https://translate.wordpress.org/projects/wp-plugins/pixel-made-simple)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/pixel-made-simple/),
check out the [SVN repository](https://plugins.svn.wordpress.org/pixel-made-simple/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/pixel-made-simple/)
by [RSS](https://plugins.trac.wordpress.org/log/pixel-made-simple/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

The complete changelog for every release is at https://pixelmadesimple.com/changelog/–
this file lists the most recent ones.

#### 0.12.7

Hardening. No change to tracking, settings or anything you can see.

 * Changed: five values have to reach the plugin byte for byte – cookie contents
   written by consent banners (JSON, Base64, percent-encoded), the request path,
   and the email address before it is hashed. A standard sanitiser would quietly
   destroy them: it strips every %XX sequence, which is how a percent-encoded path
   or a banner cookie turns into something that no longer matches. Those five now
   pass through one filter that removes control characters and nothing else – the
   character class behind log injection and truncated strings, and the one class
   that appears in none of those formats.

#### 0.12.6

Code hygiene. No change to tracking, settings or anything you can see.

 * Changed: the two form endpoints sanitise their input in the order a static analyser
   can follow. The sanitising itself is unchanged and was never missing – it was
   written in a way that made the WordPress Plugin Check report eight false alarms,
   in the one file where a false alarm costs the most attention.
 * Changed: three deliberate exceptions now say so at the line itself: the two queries
   against Borlabs’ own tables, and the version-less loading of third-party scripts–
   appending a version number to someone else’s URL has no purpose.
 * Added: the length limits on both public endpoints are now covered by tests. They
   had never been, and they are exactly what this release moved.

#### 0.12.5

One upgrade notice on the e-commerce tab instead of two. Nothing else changes.

 * Changed: the info box above the WooCommerce section said the same thing as the
   box directly below it, down to a second “Learn more” button. It only ever appeared
   when a shop plugin was detected – which is exactly when that box appears too,
   so it never added anything. The WooCommerce and SureCart boxes carry that information
   themselves.

#### 0.12.4

The free version no longer contains a licence check anywhere. Where it previously
asked “is this the paid version?” it now asks “is this code present?” – which is
what actually differs between the two packages. Nothing changes for you; the switches
you can see and use are the same ones as before.

 * Changed: every remaining gate in the admin interface asks whether the class implementing
   the feature exists, not whether a licence is active. In the free package the 
   implementation is simply absent, so its controls are absent too – rather than
   present and refusing to work.
 * Changed: the endpoint behind the instant-save toggles now names, per setting,
   the class that has to be there for the value to mean anything. A toggle that 
   could not take effect no longer stores a value.
 * Fixed: the icon on the “Upgrade to Pro” buttons was invisible. It had kept the
   cream colour from back when those buttons were blue; on the white button it has
   been there all along, just unreadable.

#### 0.12.3

Google Ads, Google Analytics 4 and the TikTok Pixel are now part of this plugin,
and every remaining limit is gone – no cap on URL events, no shortened event log,
no locked filters or exports. Nothing this plugin ships is restricted any more, 
which is what the WordPress.org plugin directory guidelines require.

 * Changed: Google Ads (gtag.js incl. Consent Mode v2), Google Analytics 4 and the
   TikTok Pixel are available here. A configuration made under Pro is picked up 
   unchanged – both variants have always used the same option keys.
 * Changed: URL events are no longer capped at two.
 * Changed: the event log keeps 3, 7, 14 or 30 days, whichever you choose, and its
   status, event and platform filters work.
 * Changed: the consent statistics offer the 30-day period, the daily breakdown 
   and the CSV export.
 * Changed: JSON export and import of the whole configuration are available.
 * Changed: form leads can be sent to TikTok and Google Ads, including Enhanced 
   Conversions for the Google conversion.
 * Changed: Pixel Made Simple Pro now covers what only it can provide – WooCommerce
   and SureCart e-commerce tracking, the TikTok Events API for server-side purchase
   events, purchase advanced matching, and first-touch/UTM attribution with automatic
   form fill. No existing Pro installation loses a feature.
 * Changed: the two remaining references to Pro in the admin are plain informational
   boxes. No padlock icons, no greyed-out controls and no upgrade prompts anywhere
   else.
 * Changed: the TikTok Events API fields (toggle, access token, test event code)
   are only rendered when the class implementing them is present. They drive the
   e-commerce purchase path and would otherwise have been controls without an effect.
 * Changed: the plugin description no longer compares this plugin to others.
 * Removed: the `FREE_EVENT_LIMIT` constant and `free_event_limit_reached()`, and`
   resolve_event_platforms()`, which enforced the per-event Google/TikTok lock server-
   side.
 * Removed: the `$is_pro` argument of `resolve_summary_days()`; the constant `FREE_SUMMARY_DAYS`
   is now `DEFAULT_SUMMARY_DAYS` and `FREE_LOG_RETENTION_DAYS` is gone.
 * Removed (free package only): `load_plugin_textdomain()`. WordPress has loaded
   translations for plugins hosted on WordPress.org by itself since version 4.6.
   Pixel Made Simple Pro is not distributed through the directory and keeps the 
   call.
 * Removed (free package only): the compiled German translation (`.po`/`.mo`) is
   no longer shipped. Translations now come from translate.wordpress.org and land
   in `wp-content/languages/`; the `.pot` template stays in the plugin.
 * Changed: `gtag.js` and the three privacy tracker scripts are registered through`
   wp_enqueue_script()` instead of being written into the page directly. Plausible’s`
   data-domain` and Umami’s `data-website-id` are attached through the `script_loader_tag`
   filter; Rybbit carries its ID in the query string as before. Nothing changes 
   for the consent gate: without consent the loader still lives as a plain string
   inside the consent bootstrap and no `src` attribute reaches the markup.
 * Changed: the debug bar’s CSS moved from an inline `<style>` block into a registered
   stylesheet (`wp_add_inline_style()`). It had to move from the footer to `wp_enqueue_scripts`
   to be printed at all.
 * Changed: superglobals are sanitised where they are read, not a line later. Five
   values are documented exceptions: they are only ever compared or hashed, never
   printed, and any sanitiser would silently change them into something else. The
   three private helpers in the form endpoints now receive their raw values as parameters
   instead of reading `$_POST` themselves, so the obligation to verify the nonce
   first is visible at the call site.
 * Changed: the configuration import reads the uploaded file through `WP_Filesystem`,
   falling back to `file_get_contents()` on installations without direct filesystem
   access so the import keeps working there.
 * Changed: every table and column name in a database query goes through the `%i`
   placeholder of `$wpdb->prepare()` instead of string interpolation. This includes
   the two queries that read Borlabs Cookie’s own tables.
 * **Breaking: minimum WordPress version raised from 5.8 to 6.3.** Sites below 6.3
   will not be offered this update. That is what makes the loading strategy (`async`/`
   defer`) available to enqueued scripts through the official API instead of a filter
   of our own.
 * **Breaking: every prefix changed from `pms` to `pxms`.** The directory guidelines
   require at least four characters, and `pms` has three. This affects class names,
   constants, option keys, both database tables, the cron hook, the attribution 
   cookie, order meta keys, AJAX actions, script handles, the JavaScript globals,
   the CSS classes and the admin page slug – a bookmark to the old settings URL 
   will no longer resolve.
 * **Breaking: the twelve public filters were renamed** – `pms_capi_blocking` is
   now `pxms_capi_blocking`, and so on for all of them. There is no compatibility
   layer. If you hook into one of them from a snippet or a child theme, update the
   name; in particular `pxms_normalize_phone`, which decides whether Google receives
   a phone number at all.
 * **Breaking: settings are not migrated.** The option keys and both tables changed
   name, so the plugin starts with its defaults after this update and the old rows
   stay behind unused. This was a deliberate decision – at the time of the rename
   the plugin ran on two test sites, and carrying migration code for them would 
   have meant carrying it forever.
 * Changed: neither package deactivates the other any more – a plugin must not do
   that. The free version checks whether a Pro package is active, and whether its
   file is actually still there, and then does not load at all: no hook, no menu,
   no tracking. It stays in the plugin list and says so; deactivate it whenever 
   you like. Should Pro be deactivated later, the free version takes over again 
   on the next request.

#### 0.12.2

Corrects the plugin header. No change to tracking behaviour, no new setting.

 * Fixed: `Plugin URI` and `Author URI` carried the same address in 0.12.1. They
   have to differ – the plugin URI describes this plugin, the author URI describes
   the person who wrote it. `Author` and `Author URI` name the author again, as 
   they did before 0.12.1.

#### 0.12.1

Prepares the free version for the WordPress.org plugin directory. No change to tracking
behaviour, no new setting.

 * New: **The plugin has its own menu icon** in the WordPress admin instead of the
   generic chart symbol. Like the built-in icons it follows your admin colour scheme
   and highlights while you are on one of its pages.
 * Changed: the _External services_ section of this readme now documents Plausible,
   Umami and Rybbit as well – which service is contacted, when data flows, and links
   to each provider’s terms and privacy policy. As before, the address contacted
   is the one you enter yourself; the plugin ships no default and never builds one.
 * Changed: the changelog shown in the plugin directory lists the most recent releases
   only. WordPress.org truncates a longer one mid-sentence, so the full history 
   now lives at https://pixelmadesimple.com/changelog/.
 * Changed: the recent changelog entries are now in English. Older ones stay as 
   they were written – an entry records what changed at the time and is not rewritten
   afterwards.
 * Added: the complete GPL-2.0 licence text now ships with the plugin.

#### 0.12.0

New _Privacy Trackers_ tab: Plausible, Umami and Rybbit can now be embedded directly–
cookieless analytics alongside the advertising pixels. Available in the free version
too.

 * New: **Embed Plausible, Umami and Rybbit.** Two fields per provider – the script
   URL from your dashboard and the site identifier. That loads the base script, 
   nothing more. The providers carry their identifier differently (Plausible `data-
   domain`, Umami `data-website-id`, Rybbit as a parameter on the URL); the plugin
   builds the snippet each one actually expects.
 * Why the full script URL instead of just the domain: an address the plugin assembled
   from a host name could go silently wrong the moment a provider changed its path
   or handed out a different filename. That is not hypothetical – Umami renamed 
   its tracker from `/umami.js` to `/script.js` in version 2, one of that release’s
   documented breaking changes. And such a failure looks like success: the script
   loads, and nothing arrives. So copy the address verbatim from your dashboard;
   the plugin ships no default and never builds one.
 * New: **A _Load without consent_ switch – per provider, off by default.** Off 
   means: the tracker waits for consent just like the Meta, Google and TikTok pixels,
   and starts after the click on “Accept” without a reload. On means: it loads immediately–
   and only it. The advertising platforms are untouched either way.
 * On how to read that switch: Section 25 TDDDG covers storing information on, or
   reading it from, a visitor’s device. A tracker that sets no cookie and uses no
   local storage is not covered by it; the GDPR level is unaffected. Whether that
   reasoning holds depends on the specific service and where it is hosted, and it
   is legally contested. The plugin makes no claim about whether a third-party service
   is compliant – it only provides the setting.
 * **Deliberately kept small:** the base script only. No custom events, no goals,
   no server-side connection, no e-commerce mapping. That is a decision, not an 
   unfinished state.
 * As long as a provider’s switch is off or one of its two fields is empty, not 
   a single line for it ends up in your page source.
 * The privacy trackers run neither through the Conversions API nor through the 
   event log nor through the consent statistics. They are not conversions, and they
   should not dilute the numbers you use to chase missing advertising conversions.
 * Changed: a site that uses only a privacy tracker and has no advertising pixel
   set up at all is now served. Until now nothing would have been output there.

## Meta

 *  Version **0.12.7**
 *  Last updated **15 hours ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.3 or higher **
 *  Tested up to **7.1.1**
 *  PHP version ** 7.4 or higher **
 * Tags
 * [consent mode](https://wordpress.org/plugins/tags/consent-mode/)[Conversions API](https://wordpress.org/plugins/tags/conversions-api/)
   [google ads](https://wordpress.org/plugins/tags/google-ads/)[Meta Pixel](https://wordpress.org/plugins/tags/meta-pixel/)
   [Tiktok Pixel](https://wordpress.org/plugins/tags/tiktok-pixel/)
 *  [Advanced View](https://wordpress.org/plugins/pixel-made-simple/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/pixel-made-simple/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/pixel-made-simple/reviews/)

## Contributors

 *   [ Dominik Seitz ](https://profiles.wordpress.org/seitzdominik/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/pixel-made-simple/)