Would you like to know which campaigns are actually driving donations? The Google Analytics addon connects your Charitable donation forms to Google Analytics 4, captures every donation event, and shows you exactly where your supporters are coming from. It tracks both browser-side and server-side conversions, so you don’t lose donations from PayPal redirects, webhook-confirmed payments, or admin-confirmed offline donations.
This guide will walk you through the steps to connect your Charitable site to GA4, enable server-side tracking, configure privacy options, and review the data Charitable captures for each donation.
Note:
Requirements: Charitable Pro 1.8.13+
The Google Analytics addon requires the Pro plan or higher.Before you get started, make sure Charitable Pro is installed and activated on your site. You’ll also need a Google Analytics 4 propertywith at least one data stream configured for your website.
In This Guide
- Setting Up the Google Analytics Addon
- Enabling Server-Side Tracking
- Configuring Consent and Privacy
- Excluding Internal Traffic
- Testing Your Connection
- Reviewing Donation Source Data in WordPress
- Understanding the Events Charitable Tracks
- Viewing Your Data in GA4
- Testing the Feature
- Troubleshooting
- Filters
- charitable_google_analytics_is_ga4_loaded
- charitable_google_analytics_purchase_payload
- charitable_google_analytics_mp_purchase_payload
- charitable_google_analytics_mp_refund_payload
- charitable_google_analytics_mp_signup_payload
- charitable_google_analytics_mp_login_payload
- charitable_google_analytics_persist_utm
- charitable_google_analytics_utm_first_touch
- charitable_google_analytics_has_consent
- charitable_google_analytics_consent_default
- charitable_google_analytics_user_id
- charitable_google_analytics_client_ip
- Actions
- Donation Meta Keys
- Cookie Names
- Settings Option Keys
- Constants
- Common Recipes
- Hook Firing Order
- Frequently Asked Questions
- Q: Will this work with PayPal Standard or other off-site gateways?
- Q: Is this GDPR compliant?
- Q: Does this conflict with Site Kit by Google or MonsterInsights?
- Q: How long does it take for events to appear in GA4 reports?
- Q: Can I exclude my staff from being tracked?
- Q: Are donations made in Charitable's test mode tracked?
Setting Up the Google Analytics Addon
Once you’ve installed and activated the addon, the GA4 settings are added to Charitable’s Advanced settings panel. To open them, go to Charitable » Settings » Advanced in your WordPress admin.
You’ll need your GA4 measurement ID, which begins with
G-followed by a string of letters and numbers. To find it, sign in to your Google Analytics account, open Admin » Data Streams, and select your web stream. The measurement ID is shown in the upper right corner of the stream details page.Back in your WordPress admin, paste the measurement ID into the Google Analytics field and then click Save Changes at the bottom of the page.
Note: The addon validates that the measurement ID begins with
G-. If you accidentally paste a Google Tag Manager container ID (which begins withGTM-) or a legacy Universal Analytics property ID (UA-), tracking won’t work. The current GA4 format is the only one supported.Enabling Server-Side Tracking
Browser-side tracking with gtag.js works well when donors complete payment on your site and reach the donation receipt page. But many donations finish in places the browser can’t see: a PayPal Standard redirect where the donor closes the tab, a Stripe webhook that confirms payment hours later, or an admin manually marking an offline donation as paid. Without server-side tracking, those donations never reach Google Analytics.
Charitable’s server-side tracking sends a confirmed
purchaseevent to GA4 the moment a donation status changes to Paid, regardless of whether the donor’s browser is involved. The same path also fires arefundevent when a donation is refunded.To enable server-side tracking, you’ll need a Measurement Protocol API secret from your GA4 property. To create one, sign in to Google Analytics, open Admin » Data Streams, select your web stream, scroll down to Measurement Protocol API secrets, and click Create. Give the secret a nickname so you can identify it later.
Once you have the secret, copy its value, return to Charitable » Settings » Advanced, and paste it into the GA4 Measurement Protocol API Secret field. Save your changes.
Note: The API secret is optional. If you leave it blank, Charitable will still track on-site donations through the browser. The server-side path only activates when both the measurement ID and the API secret are set.
Server-side and browser-side tracking share an idempotency flag, so a donation that completes on-site and is confirmed by webhook will only fire one
purchaseevent in GA4 – never two. The first path to fire wins.Configuring Consent and Privacy
The addon ships full Google Consent Mode v2 support, which is required for traffic from the European Economic Area under Google’s March 2024 enforcement rules. Without it, donors who deny analytics consent disappear from GA4 entirely. With it, GA4 still receives modeled conversions and cookieless pings.
The consent state is sent in the page head, before
gtag.jsloads, with all four required signals:analytics_storage,ad_storage,ad_user_data, andad_personalization. The values come from whatever consent management platform you have installed.Consent Integration Setting
In the Advanced settings panel, you’ll see a Consent Integration checkbox below the API secret field. This setting controls how the addon talks to your CMP through the WP Consent API framework, which is supported by Cookiebot, CookieYes, Complianz, Iubenda, OneTrust, and most other major consent plugins.
- Enabled (default) – the addon checks
wp_has_consent('statistics')at the moment of donation and only fires server-side events for donors who have granted analytics consent. Choose this if you have a CMP installed and want server-side events to honor donor consent.- Disabled – the addon ignores WP Consent API state and fires server-side events for every completed donation. Choose this only if you don’t have a CMP, or if your legal team has confirmed donor data can be sent to Google without analytics consent.
The consent state is captured at the moment the donation is created and stored on the donation record. That means a donor who later changes their mind in your CMP doesn’t retroactively block events for donations they already made – the snapshot at donation time is authoritative for that donation.
IP Anonymization
Donor IP addresses are always anonymized before being sent to Google. Charitable truncates IPv4 addresses to
/24(the last octet is zeroed) and IPv6 addresses to/48(the last 80 bits are zeroed) before passing them to GA4 as theip_overrideparameter.The result: Google can geolocate donors at the country and region level – useful for fundraising attribution – but can never see a donor’s exact IP. The full IP is never stored in your WordPress database either.
Excluding Internal Traffic
If your team logs in to test campaigns or manage donations, you probably don’t want their browsing showing up in GA4 alongside real donor traffic. The Exclude tracking for roles field lets you skip tracking entirely for logged-in users in specific roles.
From the Advanced settings, find Exclude tracking for roles and check the boxes for any roles you want to exclude. Common choices are Administrator and Editor for a small team, or Administrator only if you want fundraising staff to be tracked. Save your changes.
For excluded users, the addon won’t load
gtag.json the frontend and won’t fire any events. Logged-out visitors and users in unselected roles are tracked normally.Testing Your Connection
The biggest source of confusion with any analytics integration is “did I configure this correctly?” The addon includes a one-click test that fires a real event to GA4 with debug mode enabled, then reports the result inline.
From Charitable » Settings » Advanced, scroll to the Test GA4 Connection section and click Send Test Event to GA4.
The button does two things in sequence. First, it sends your payload to GA4’s debug endpoint, which validates the structure and rejects invalid measurement IDs or API secrets with a descriptive error. Second, it sends the same event to GA4’s live endpoint with
debug_modeturned on, so the event appears in GA4 » Admin » DebugView within a few seconds.If the test succeeds, you’ll see a green checkmark with a confirmation message naming the test event (
charitable_test_event). If it fails, the message will tell you why – the most common causes are an invalid API secret, a typo in the measurement ID, or a network connectivity issue between your server and Google.The test event is harmless. It uses a synthetic client ID so it won’t show up alongside real donor data in your standard reports.
Reviewing Donation Source Data in WordPress
Every donation in your Charitable admin shows a Google Analytics panel in the right side column of the donation edit screen. The panel only appears when there’s data captured for that donation, so older donations from before the addon was installed won’t show it.
The panel groups the captured data into four sections:
- Source (UTM) – shows the
utm_source,utm_medium,utm_campaign,utm_term,utm_content, andutm_idvalues from the URL the donor used to reach your site. Only fields with captured values are shown.- GA4 Session – shows the donor’s GA4 client ID and session ID, parsed from the
_gacookie at the moment of donation. These let you cross-reference the donation in GA4 reports if you need to investigate a specific transaction.- Consent at insert – shows the donor’s WP Consent API state for the
statisticsandmarketingcategories at the moment they donated. Useful for compliance audits.- GA4 events fired – shows the timestamp when the
purchaseand (if applicable)refundevents were sent to GA4. If a donation has nopurchasetimestamp, that means the event hasn’t been sent yet (still pending) or was suppressed by your consent or role-exclusion settings.The panel loads collapsed by default to keep the donation edit screen clean. Click the Google Analytics title bar to expand it. WordPress remembers your preference per user.
UTM Tagging Your Campaigns
For the Source (UTM) section to capture data, the donor needs to arrive at your site through a URL containing UTM parameters. A typical campaign URL might look like:
https://example.org/donate/?utm_source=email&utm_medium=newsletter&utm_campaign=spring-2026You’d send that link in your fundraising email instead of the bare donation page URL. When the donor clicks through, Charitable saves those UTM values in a first-party cookie that lives for 30 days. Whenever they donate within that window, the UTM values are attached to the donation record and forwarded to GA4 as the
source,medium, andcampaignevent parameters.By default the addon uses last-touch attribution: if the donor visits with one set of UTMs, then later visits with a different set, the most recent set wins. Developers can switch to first-touch attribution with the
charitable_google_analytics_utm_first_touchfilter.Understanding the Events Charitable Tracks
Charitable fires the following GA4 events at different points in the donation lifecycle. All of them appear in your GA4 reports automatically – no custom event configuration is required on the GA4 side.
purchase– fires when a donation is confirmed paid. Sends standard GA4 ecommerce fields:transaction_id(the donation ID),value,currency, and anitems[]array with the campaign as the line item, categorized asRecurringorOne-Time.refund– fires when a donation is transitioned to refunded. Matches the originalpurchaseevent’stransaction_idso GA4 cross-references the two automatically. Net revenue in your GA4 reports stays accurate.sign_up– fires when a donor creates a WordPress user account on your site. The event includes a hashed identifier so the same donor’s later donations are correlated to the same person across browsers and devices.login– fires when a returning donor logs in. Useful for retention reporting in GA4.donation_button_clickanddonate_now_click– browser-only click events for top-of-funnel signal. They fire when a donor clicks a donate button, before the form has been submitted.Donations made in Charitable’s test mode are tagged with
test_mode: truein the event parameters, so you can filter them out of your reports. To do that in GA4, create a comparison or audience that excludes events wheretest_modeequalstrue.Viewing Your Data in GA4
Once you’ve made a test donation (or had a real one come through), Google Analytics has three places to verify the data is landing.
Realtime
The fastest way to confirm tracking is working. From your GA4 property, open Reports » Realtime. Within about 30 seconds of a donation completing, you’ll see the
purchaseevent in the Event count by Event name card on the right. Click any event name to drill into its parameters.DebugView
For step-by-step verification of a specific event, open Admin » DebugView. Events tagged with
debug_modeappear here in real time, with full parameter detail. The Test Connection button automatically tags its events for DebugView, and you can also enable debug mode site-wide by addingdefine('CHARITABLE_DEBUG', true);to yourwp-config.php.Standard Reports
For revenue analysis, the most useful report is Reports » Monetization » Ecommerce purchases. This report aggregates your
purchaseevents into revenue totals broken down by campaign (theitem_name), category (recurring vs one-time), and date. Refunds are subtracted automatically thanks to GA4’s transaction ID matching. Standard reports populate within 24 to 48 hours.For traffic source analysis, look at Reports » Acquisition » Traffic acquisition. Your UTM-tagged campaigns will appear as separate rows, with revenue, conversion rate, and engagement metrics for each.
Testing the Feature
The fastest end-to-end test is to make a real donation through your site using a test gateway like Stripe Test Mode. After the donation completes, open the donation in Charitable » Donations, expand the Google Analytics panel, and confirm the GA4 events firedsection shows a
purchasetimestamp. Then check GA4 » Reports » Realtime to confirm the event appears within 30 seconds.If you’re testing the refund event, transition the donation to Refunded from the Donations list. The metabox should add a
refundtimestamp, and GA4 Realtime should show therefundevent within 30 seconds.Troubleshooting
Events Aren’t Appearing in GA4
If your test donations aren’t landing in GA4, work through these checks in order:
- From Charitable » Settings » Advanced, confirm the Google Analytics field contains your measurement ID and not a GTM container ID or legacy UA property.
- Click the Send Test Event to GA4 button. The error message will name the specific problem (invalid API secret, invalid measurement ID, network error).
- Check whether you’re logged in with a role you’ve added to Exclude tracking for roles. Excluded users don’t generate events, even when testing. Log out and try in an incognito window.
- Disable any browser ad blockers (uBlock Origin, AdBlock Plus, Brave Shields) for your domain. They block
gtag.jsfrom loading on the frontend.Site Kit by Google is Already Active
If you have Google Site Kit installed and connected to your GA4 property, Charitable defers loading
gtag.jsto Site Kit. This prevents the page from loading the GA4 script twice. The donation events will still fire through Site Kit’s gtag instance.If you’ve installed Site Kit but haven’t connected the Analytics module, Charitable’s deferral is unnecessary. Developers can override it by returning
falsefrom thecharitable_google_analytics_is_ga4_loadedfilter.Charitable Conversion Tracking GTM Conflict Notice
If you have the Charitable Conversion Tracking addon installed with a GTM container ID configured, Charitable will show an admin notice on Charitable settings pages explaining that
gtag.jsis being suppressed. This is intentional – your GTM container is expected to load GA4 itself, and loadinggtag.json top would double-count pageviews.If your GTM container does not actually include a GA4 tag, this suppression is incorrect for your setup. Override it with the
charitable_google_analytics_is_ga4_loadedfilter.Server-Side Events Aren’t Firing
Server-side tracking only activates when both the measurement ID and the Measurement Protocol API secret are set. If your
refundevents or off-site donations aren’t appearing in GA4 but on-site donations are, the API secret is likely missing or invalid. Use the Test Connection button to confirm.If the API secret is set and the test passes but real status changes aren’t generating events, check the donation’s Google Analyticsmetabox. The Consent at insert section may show
statistics: Denied, in which case the addon is correctly skipping server-side events for that donor’s donations.That’s it! You now have GA4 tracking your Charitable donations end-to-end, with attribution data flowing into both Google Analytics and your WordPress admin. Next, see Connecting Other Charitable Extensions to pair this addon with Conversion Tracking for Meta and TikTok pixels, or with the Recurring addon for subscription analytics.
Filters
The addon exposes 12 filters covering loader detection, payload customization, consent, attribution, and identity hashing. Filter names follow a
charitable_google_analytics_*prefix and pass the value being filtered as the first argument.
charitable_google_analytics_is_ga4_loadedWhether another plugin is already loading GA4 on the page. When
true, the addon will not inject its owngtag.jsto prevent double-loading. Detected loaders include MonsterInsights, Site Kit by Google, and Charitable Conversion Tracking with a GTM container ID configured.apply_filters( 'charitable_google_analytics_is_ga4_loaded', $is_loaded );Use this when you have a non-default GA4 loader (e.g. a custom theme tag) that the addon doesn’t auto-detect. Returning
truesuppresses the addon’s owngtag.jsinjection.
charitable_google_analytics_purchase_payloadThe browser-side
purchaseevent payload built on the donation receipt page (Phase A). Fires before the inline<script>block is emitted in the footer.apply_filters( 'charitable_google_analytics_purchase_payload', array $payload, Charitable_Donation $donation );The
$payloadarray contains GA4 ecommerce fields (transaction_id,value,currency,items). Returning an empty array ([]) skips firing the event for that donation.
charitable_google_analytics_mp_purchase_payloadThe server-side Measurement Protocol
purchasepayload (Phase B). Fires before thewp_remote_post()call to GA4.apply_filters( 'charitable_google_analytics_mp_purchase_payload', array $payload, Charitable_Donation $donation );The
$payloadis the full MP body (client_id, optionaluser_id,events[]). Returning a payload with emptyeventsskips the call.
charitable_google_analytics_mp_refund_payloadSame shape as
mp_purchase_payload, but fired before the server-siderefundevent POST.apply_filters( 'charitable_google_analytics_mp_refund_payload', array $payload, Charitable_Donation $donation );
charitable_google_analytics_mp_signup_payloadThe server-side
sign_uppayload built when a new WordPress user is registered.apply_filters( 'charitable_google_analytics_mp_signup_payload', array $payload, WP_User $user );Use this to suppress sign-up events for specific roles or to inject custom event parameters (e.g. registration source).
charitable_google_analytics_mp_login_payloadThe server-side
loginpayload built when a WordPress user logs in.apply_filters( 'charitable_google_analytics_mp_login_payload', array $payload, WP_User $user );A common use is to skip login events for users with administrative capabilities.
charitable_google_analytics_persist_utmWhether the addon should persist UTM parameters from the request URL into first-party cookies on
init. Defaulttrue.apply_filters( 'charitable_google_analytics_persist_utm', $persist );Returning
falsedisables UTM cookie writes entirely. Useful for sites that want to handle UTM persistence themselves through a custom mechanism.
charitable_google_analytics_utm_first_touchWhether to use first-touch UTM attribution instead of the default last-touch. Default
false.apply_filters( 'charitable_google_analytics_utm_first_touch', $first_touch );When
true, a UTM cookie is written only if it does not already exist. The first UTM the donor was attributed to wins for the 30-day cookie window.
charitable_google_analytics_has_consentThe consent decision for a given category at the time of evaluation. Receives the WP Consent API result and lets you override.
apply_filters( 'charitable_google_analytics_has_consent', bool $consent, string $category, // 'statistics' or 'marketing' int $donation_id // 0 in live mode, donation ID in stored mode );Live mode (
$donation_id === 0) is used for browser-side gating likegtag.jsinjection. Stored mode ($donation_id > 0) is used for server-side MP calls and reads consent state captured at donation insert. Returningfalsesuppresses tracking for that category.
charitable_google_analytics_consent_defaultThe Consent Mode v2 default state emitted in the document head before
gtag.jsloads.apply_filters( 'charitable_google_analytics_consent_default', array $consent_default );
$consent_defaultcontains four keys:ad_user_data,ad_personalization,ad_storage, andanalytics_storage, each set to'granted'or'denied'. Returning'granted'for all four effectively disables Consent Mode v2 modeling for this page load.
charitable_google_analytics_user_idThe hashed user ID attached to MP payloads as
user_id. The default issha256(normalized_email), where the email is lowercased and stripped of subaddress.apply_filters( 'charitable_google_analytics_user_id', string $user_id, Charitable_Donation $donation );Returning an empty string suppresses the
user_idfield entirely. The filter receives the final hash, not the raw email – if you need a different identity scheme, return your own stable per-human hash here.
charitable_google_analytics_client_ipThe client IP used as the source for IP anonymization. Defaults to
REMOTE_ADDR. Sites behind a CDN or reverse proxy that puts the donor’s real IP in a forwarded header should override this.apply_filters( 'charitable_google_analytics_client_ip', string $ip );The returned value is then truncated to
/24(IPv4) or/48(IPv6) before being passed to GA4 as theip_overrideparameter.Actions
The addon fires two actions for every server-side Measurement Protocol call – one on success, one on failure. Both let third-party integrations react to GA4 conversion delivery in real time.
charitable_google_analytics_event_sentFires after a 2xx response from
mp/collect.do_action( 'charitable_google_analytics_event_sent', string $event_label, // e.g. 'purchase', 'refund', 'sign_up', 'login' int $donation_id, // 0 for non-donation events array $payload, // the MP body that was sent int $http_code // typically 204 );Use this to mirror events to a CDP like HubSpot or Segment, fire a Zapier webhook, update an analytics dashboard, or anything else that should react to a confirmed conversion.
charitable_google_analytics_event_failedFires on either a network error (WP_Error response) or a non-2xx HTTP status.
do_action( 'charitable_google_analytics_event_failed', string $event_label, int $donation_id, array $payload, string $error // WP_Error message or 'HTTP <code>' );Use this to alert ops, queue a retry through your own job system, or fall back to an alternative pipeline.
Donation Meta Keys
The addon stores everything it captures about a donation as standard WordPress post meta. You can query these directly with
get_post_meta()or via WP-CLI’swp post meta get.
Meta key Set by Type What it contains _charitable_ga_client_idcapture_session()oncharitable_after_save_donationstring Parsed GA4 client_id from the donor’s _gacookie at donation insert. Format:<part1>.<part2>._charitable_ga_session_idSame string Parsed GA4 session_id from the donor’s _ga_<container>cookie._charitable_ga_ip_overrideSame string Anonymized donor IP ( /24IPv4 or/48IPv6)._charitable_ga_consent_statisticsSame 'granted'or unsetWP Consent API state for the statisticscategory at insert. Empty meta is treated as permissive._charitable_ga_consent_marketingSame 'granted'or unsetSame for marketing._charitable_ga_utm_sourceSame string UTM source from the donor’s first-party cookie (or $_REQUESTfallback)._charitable_ga_utm_mediumSame string UTM medium. _charitable_ga_utm_campaignSame string UTM campaign. _charitable_ga_utm_termSame string UTM term. _charitable_ga_utm_contentSame string UTM content. _charitable_ga_utm_idSame string UTM ID. _charitable_ga_purchase_firedfire_purchase_event()(Phase A) andfire_purchase_mp()(Phase B)MySQL datetime string Timestamp of the first successful purchaseevent. Shared between Phase A and Phase B – whichever fires first sets it._charitable_ga_refund_firedfire_refund_mp()MySQL datetime string Timestamp of the successful refundevent. Separate from the purchase flag.All meta keys are prefixed with a single underscore, which means they’re hidden from the standard custom fields UI in the donation edit screen. They appear in the addon’s “Google Analytics” metabox instead.
Cookie Names
The addon writes the following cookies on the donor’s browser:
charitable_ga_utm_source,charitable_ga_utm_medium,charitable_ga_utm_campaign,charitable_ga_utm_term,charitable_ga_utm_content,charitable_ga_utm_id– first-party cookies set oninitwhenever a UTM parameter is present in the request URL. Lifetime 30 days, path/, SameSiteLax,Securewhen SSL is active.It also reads these cookies set by gtag.js itself:
_ga– GA4 client_id source_ga_<container>– GA4 session_id source. The<container>portion is the measurement ID with the leadingG-stripped.Settings Option Keys
The addon’s settings live in WordPress’s
charitable_settingsoption. You can read them viacharitable_get_option( $key, $default ):
Option key Type Default Description ga4_tracking_idstring ''The GA4 measurement ID ( G-XXXXXXXXXX).ga4_mp_api_secretstring ''The Measurement Protocol API secret. Required for server-side tracking. ga4_consent_integrationbool 1Whether to honor WP Consent API state. ga4_excluded_rolesstring[] []Array of role slugs to exclude from tracking. Constants
Two WordPress constants change the addon’s runtime behavior:
CHARITABLE_DEBUG(true/false) – when true, the addon writes step-by-step breadcrumbs to Tools » Logs withsource: google-analytics, and addsdebug_mode: 1to all GA4 MP event payloads so they appear in GA4 » Admin » DebugView. Define inwp-config.phpfor development sites.SCRIPT_DEBUG(true/false) – when true, the addon enqueues the unminifiedcharitable-google-analytics.jssource file instead of the minified production build. Useful when debugging frontend behavior.Common Recipes
Switch UTM attribution from last-touch to first-touch
add_filter( 'charitable_google_analytics_utm_first_touch', '__return_true' );The first UTM the donor was attributed to within the 30-day cookie window stays. Subsequent visits with different UTMs are ignored.
Capture the donor’s real IP behind Cloudflare
add_filter( 'charitable_google_analytics_client_ip', function( $ip ) { if ( ! empty( $_SERVER['HTTP_CF_CONNECTING_IP'] ) ) { $candidate = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CF_CONNECTING_IP'] ) ); if ( filter_var( $candidate, FILTER_VALIDATE_IP ) ) { return $candidate; } } return $ip; } );The returned IP is still anonymized to
/24(IPv4) or/48(IPv6) before being sent to GA4 – the filter just changes which IP gets anonymized.Mirror every confirmed donation to a CDP
add_action( 'charitable_google_analytics_event_sent', function( $event_label, $donation_id, $payload, $http_code ) { if ( 'purchase' !== $event_label ) { return; } // POST to your CDP, fire a Zapier webhook, etc. wp_remote_post( 'https://cdp.example.com/events', array( 'body' => wp_json_encode( $payload ), 'headers' => array( 'Content-Type' => 'application/json' ), 'timeout' => 5, ) ); }, 10, 4 );Both successful and failed events fire actions, so you can also retry failed events through your own job system.
Skip login events for administrators
add_filter( 'charitable_google_analytics_mp_login_payload', function( $payload, $user ) { if ( user_can( $user, 'manage_options' ) ) { return array_merge( $payload, array( 'events' => array() ) ); } return $payload; }, 10, 2 );An empty
eventsarray tells the addon to skip the MP call without disturbing other event types.Add a custom event parameter to every purchase
add_filter( 'charitable_google_analytics_mp_purchase_payload', function( $payload, $donation ) { if ( ! empty( $payload['events'][0]['params'] ) ) { $payload['events'][0]['params']['organization_id'] = '12345'; } return $payload; }, 10, 2 );Use this for multi-org WordPress installs where each donation should carry an organization tag for GA4 segmentation.
Override the donor user_id with your own identity scheme
add_filter( 'charitable_google_analytics_user_id', function( $hashed_email, $donation ) { $crm_id = get_post_meta( $donation->ID, '_my_crm_donor_id', true ); if ( $crm_id ) { return hash( 'sha256', 'crm:' . $crm_id ); } return $hashed_email; }, 10, 2 );The filter receives the addon’s default hash; you can replace it with your own per-human stable hash. Returning an empty string suppresses the
user_idfield entirely.Hook Firing Order
For a typical donation flow that completes on-site, the relevant hooks fire in this order:
init(priority 10) –charitable_google_analytics_persist_utm()writes UTM cookies if the request URL has UTM parameters.wp_head(priority 1) – the inline Consent Mode v2 default andgtag.jsscript tag are emitted, gated bycharitable_google_analytics_is_ga4_loadedand the role-exclusion check.wp_footer(priority 1) – thegtag('js')andgtag('config')calls are emitted.- Donor submits the donation form. AJAX or redirect-driven gateway flow runs.
charitable_after_save_donation(priority 10) –capture_session()reads the donor’s cookies and stores GA4 clientid, sessionid, anonymized IP, UTM values, and consent state as donation meta.- Gateway confirms payment (synchronously for on-site, via webhook for off-site).
charitable_donation_status_changed(priority 10) –fire_purchase_mp()POSTs the server-sidepurchaseevent. The actioncharitable_google_analytics_event_sentfires on success.charitable_donation_receipt_page(browser only) –fire_purchase_event()adds awp_footercallback that emits the inlinegtag('event', 'purchase', ...)script. The_charitable_ga_purchase_firedmeta is set inside that wp_footer callback (not synchronously) so email rendering of the receipt does not trip the idempotency flag.For a refund: step 7 above re-fires with
new_status === 'charitable-refunded', andfire_refund_mp()POSTs therefundevent.For a sign_up or login: only steps 1, 2, 3 of the above apply for browser context. Steps 5-8 are replaced by
user_registerorwp_login, which triggerfire_signup_mp()orfire_login_mp()respectively.That’s it! You now have the full hook surface for the Charitable Google Analytics addon. Next, see the Complete Guide to Google Analytics in Charitable for setup and admin documentation, or the Charitable Developer Documentation hub for hooks across the rest of Charitable.
Frequently Asked Questions
Q: Will this work with PayPal Standard or other off-site gateways?
A: Yes, as long as you’ve configured the GA4 Measurement Protocol API Secret. Charitable’s server-side path catches every donation that transitions to Paid, regardless of whether the donor’s browser ever returned to your site.
Q: Is this GDPR compliant?
A: Charitable supports GDPR and EEA compliance through Google Consent Mode v2 and the WP Consent API framework. Donor IPs are anonymized before transmission, and donor emails are hashed to a one-way SHA-256 digest before becoming the GA4 user ID. The full email is never sent to Google.
Q: Does this conflict with Site Kit by Google or MonsterInsights?
A: No. Charitable auto-detects both plugins and defers loading
gtag.jswhen either is active, so you never end up with the GA4 script loaded twice on the same page. Donation events still fire through whichever loader is in charge.Q: How long does it take for events to appear in GA4 reports?
A: Realtime and DebugView show events within about 30 seconds. Standard reports (including Monetization » Ecommerce purchases) populate within 24 to 48 hours.
Q: Can I exclude my staff from being tracked?
A: Yes – use the Exclude tracking for roles field in Charitable » Settings » Advanced and select the WordPress roles you want to exclude. Excluded users skip both the browser-side and the role-applicable parts of server-side tracking.
Q: Are donations made in Charitable’s test mode tracked?
A: Yes, but they’re tagged with
test_mode: truein the event parameters so you can filter them out of your GA4 reports. Create a GA4 comparison or audience that excludes events wheretest_modeequalstrueto keep your production reports clean.Q: Are these hooks stable across versions?
A: All hooks documented here were introduced in 1.1.0 and are part of the addon’s public API. Filter and action signatures are versioned via the
@sincetag in the source. Breaking changes will be announced in the changelog with a deprecation notice in the prior release.Q: How do I disable a specific event entirely?
A: Use the corresponding payload filter and return an array with empty
events. For example, to suppress all server-siderefundevents:add_filter( 'charitable_google_analytics_mp_refund_payload', function( $payload ) { return array_merge( $payload, array( 'events' => array() ) ); } );Q: Can I add custom dimensions to GA4 events?
A: Yes. GA4 custom dimensions are sent as event parameters. Use the
charitable_google_analytics_mp_purchase_payload(or the matching filter for other events) to inject your custom parameter into$payload['events'][0]['params']. Make sure the parameter name matches your custom dimension’s “event parameter name” in the GA4 admin.Q: How do I test that my custom hook is firing?
A: Define
define( 'CHARITABLE_DEBUG', true );inwp-config.php, then check Tools » Logs filtered by sourcegoogle-analytics. Successful MP calls log info-level entries. Add anerror_log()call inside your hook for one-off debugging, or use Query Monitor’s “Hooks & Actions” panel for a live view.Q: Does the addon work with WP-CLI?
A: Yes. UTM persistence skips on
wp_doing_ajax()and CLI contexts (no cookies to set), but server-side hooks likecharitable_donation_status_changedfire correctly when triggered through WP-CLI commands. Donation meta is queryable viawp post meta get <donation-id> _charitable_ga_purchase_fired.Q: Can I extend the addon with my own custom event types?
A: Yes. The
charitable_google_analytics_post_mp_event()helper is internal but the actions it fires (event_sent/event_failed) make it easy to add your own server-side event types. Wire your event-firing function to the appropriate Charitable action, build the MP payload yourself, and POST to the same endpoint the addon uses. The MP credentials helpercharitable_google_analytics_get_mp_credentials()is also public.
Whether you’re migrating from another platform or consolidating your records, moving your data to Charitable is now faster and more flexible than ever. We’ve streamlined the process so you can bring over your entire fundraising history in just a few clicks.

🔄 Native GiveWP, Donorbox, & GiveButter Support: Switching from a major platform? Our dedicated migration tools handle the heavy lifting, automatically mapping your donors and donations directly into Charitable—no technical skills required.
📂 Universal CSV Import: Moving from a custom system or a specialized CRM? If you can export it to a CSV, you can import it here. Our smart mapping tool lets you align your columns to Charitable fields like names, emails, phone numbers, and addresses in seconds.
⚡ Instant Donor Profiles & Custom Tags: Automatically create rich donor profiles and bring in custom tags to keep your data organized. Segment and engage your supporters from day one with a clean, professional database structure.
Ready to make the switch?




