Charitable Documentation

Learn how to make the most of Charitable with clear, step-by-step instructions.

A Complete Guide to Google Analytics in Charitable

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

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 with GTM-) 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 purchase event to GA4 the moment a donation status changes to Paid, regardless of whether the donor’s browser is involved. The same path also fires a refund event 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 purchase event 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.js loads, with all four required signals: analytics_storagead_storagead_user_data, and ad_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 the ip_override parameter.

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.js on 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_mode turned 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_sourceutm_mediumutm_campaignutm_termutm_content, and utm_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 _ga cookie 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 statistics and marketing categories at the moment they donated. Useful for compliance audits.
  • GA4 events fired – shows the timestamp when the purchase and (if applicable) refund events were sent to GA4. If a donation has no purchase timestamp, 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-2026

You’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 sourcemedium, and campaign event 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), valuecurrency, and an items[] array with the campaign as the line item, categorized as Recurring or One-Time.
  • refund – fires when a donation is transitioned to refunded. Matches the original purchase event’s transaction_id so 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_click and donate_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: true in 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 where test_mode equals true.

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 purchase event 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_mode appear 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 adding define('CHARITABLE_DEBUG', true); to your wp-config.php.

Standard Reports

For revenue analysis, the most useful report is Reports » Monetization » Ecommerce purchases. This report aggregates your purchase events into revenue totals broken down by campaign (the item_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 purchase timestamp. 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 the refund event 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.js from 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.js to 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 false from the charitable_google_analytics_is_ga4_loaded filter.

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.js is being suppressed. This is intentional – your GTM container is expected to load GA4 itself, and loading gtag.js on 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_loaded filter.

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_loaded

Whether another plugin is already loading GA4 on the page. When true, the addon will not inject its own gtag.js to 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 own gtag.js injection.

charitable_google_analytics_purchase_payload

The browser-side purchase event 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 $payload array contains GA4 ecommerce fields (transaction_idvaluecurrencyitems). Returning an empty array ([]) skips firing the event for that donation.

charitable_google_analytics_mp_purchase_payload

The server-side Measurement Protocol purchase payload (Phase B). Fires before the wp_remote_post() call to GA4.

apply_filters(
    'charitable_google_analytics_mp_purchase_payload',
    array $payload,
    Charitable_Donation $donation
);

The $payload is the full MP body (client_id, optional user_idevents[]). Returning a payload with empty eventsskips the call.

charitable_google_analytics_mp_refund_payload

Same shape as mp_purchase_payload, but fired before the server-side refund event POST.

apply_filters(
    'charitable_google_analytics_mp_refund_payload',
    array $payload,
    Charitable_Donation $donation
);

charitable_google_analytics_mp_signup_payload

The server-side sign_up payload 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_payload

The server-side login payload 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_utm

Whether the addon should persist UTM parameters from the request URL into first-party cookies on init. Default true.

apply_filters( 'charitable_google_analytics_persist_utm', $persist );

Returning false disables UTM cookie writes entirely. Useful for sites that want to handle UTM persistence themselves through a custom mechanism.

charitable_google_analytics_utm_first_touch

Whether 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_consent

The 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 like gtag.js injection. Stored mode ($donation_id > 0) is used for server-side MP calls and reads consent state captured at donation insert. Returning false suppresses tracking for that category.

charitable_google_analytics_consent_default

The Consent Mode v2 default state emitted in the document head before gtag.js loads.

apply_filters(
    'charitable_google_analytics_consent_default',
    array $consent_default
);

$consent_default contains four keys: ad_user_dataad_personalizationad_storage, and analytics_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_id

The hashed user ID attached to MP payloads as user_id. The default is sha256(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_id field 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_ip

The 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 the ip_override parameter.

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_sent

Fires 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_failed

Fires 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’s wp post meta get.

Meta keySet byTypeWhat it contains
_charitable_ga_client_idcapture_session() on charitable_after_save_donationstringParsed GA4 client_id from the donor’s _gacookie at donation insert. Format: <part1>.<part2>.
_charitable_ga_session_idSamestringParsed GA4 session_id from the donor’s _ga_<container>cookie.
_charitable_ga_ip_overrideSamestringAnonymized donor IP (/24 IPv4 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_sourceSamestringUTM source from the donor’s first-party cookie (or $_REQUESTfallback).
_charitable_ga_utm_mediumSamestringUTM medium.
_charitable_ga_utm_campaignSamestringUTM campaign.
_charitable_ga_utm_termSamestringUTM term.
_charitable_ga_utm_contentSamestringUTM content.
_charitable_ga_utm_idSamestringUTM ID.
_charitable_ga_purchase_firedfire_purchase_event() (Phase A) and fire_purchase_mp() (Phase B)MySQL datetime stringTimestamp of the first successful purchase event. Shared between Phase A and Phase B – whichever fires first sets it.
_charitable_ga_refund_firedfire_refund_mp()MySQL datetime stringTimestamp 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_sourcecharitable_ga_utm_mediumcharitable_ga_utm_campaigncharitable_ga_utm_termcharitable_ga_utm_contentcharitable_ga_utm_id – first-party cookies set on init whenever a UTM parameter is present in the request URL. Lifetime 30 days, path /, SameSite LaxSecure when 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 leading G-stripped.

Settings Option Keys

The addon’s settings live in WordPress’s charitable_settings option. You can read them via charitable_get_option( $key, $default ):

Option keyTypeDefaultDescription
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_integrationbool1Whether 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 with source: google-analytics, and adds debug_mode: 1 to all GA4 MP event payloads so they appear in GA4 » Admin » DebugView. Define in wp-config.php for development sites.
  • SCRIPT_DEBUG (true/false) – when true, the addon enqueues the unminified charitable-google-analytics.js source 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 events array 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_id field entirely.

Hook Firing Order

For a typical donation flow that completes on-site, the relevant hooks fire in this order:

  1. init (priority 10) – charitable_google_analytics_persist_utm() writes UTM cookies if the request URL has UTM parameters.
  2. wp_head (priority 1) – the inline Consent Mode v2 default and gtag.js script tag are emitted, gated by charitable_google_analytics_is_ga4_loaded and the role-exclusion check.
  3. wp_footer (priority 1) – the gtag('js') and gtag('config') calls are emitted.
  4. Donor submits the donation form. AJAX or redirect-driven gateway flow runs.
  5. 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.
  6. Gateway confirms payment (synchronously for on-site, via webhook for off-site).
  7. charitable_donation_status_changed (priority 10) – fire_purchase_mp() POSTs the server-side purchaseevent. The action charitable_google_analytics_event_sent fires on success.
  8. charitable_donation_receipt_page (browser only) – fire_purchase_event() adds a wp_footer callback that emits the inline gtag('event', 'purchase', ...) script. The _charitable_ga_purchase_fired meta 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', and fire_refund_mp() POSTs the refund event.

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_register or wp_login, which trigger fire_signup_mp() or fire_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.js when 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: true in the event parameters so you can filter them out of your GA4 reports. Create a GA4 comparison or audience that excludes events where test_mode equals true to 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 @since tag 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-side refundevents:

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 ); in wp-config.php, then check Tools » Logs filtered by source google-analytics. Successful MP calls log info-level entries. Add an error_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 like charitable_donation_status_changed fire correctly when triggered through WP-CLI commands. Donation meta is queryable via wp 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 helper charitable_google_analytics_get_mp_credentials() is also public.

Still have questions? We’re here to help!

Last Modified:

What's New In Charitable

View The Latest Updates
🔔 Subscribe to get our latest updates
📧 Subscribe to Emails

Email Subscription

Join our Newsletter

We won’t spam you. We only send an email when we think it will genuinely help you. Unsubscribe at any time!

Improvement Migrations

↔️ Importing From GiveWP, Donorbox, GiveButter… even CSV!

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?

Check out our GiveWP Migration Guide

Learn more about our Import Tools

Improvement Payments

💳 New Braintree Features For Your European Donors

With the release of Braintree addon version 1.3.0, you can now empower your European donors with the payment methods they trust and prefer, making giving seamless for international supporters.

🌍 Six New European Payment Methods: Support popular local options like iDEAL (Netherlands), Bancontact (Belgium), BLIK (Poland), and more to meet donors where they are.

⚡ Frictionless Donor Experience: These bank-based methods allow donors to authenticate directly with their own bank in a secure popup… no credit card numbers required.

⚙️ Automatic Currency Sync: No complex setup needed. The builder automatically displays the correct payment buttons based on your site’s currency (EUR or PLN), ensuring a relevant experience for every visitor.

Campaigns New

🖼️ Campaign Featured Images: Pro-Level Visuals Made Simple

With the new Campaign Featured Image setting in our visual builder, you now have a single, dedicated place to manage how your fundraisers look across your entire site and beyond.

🖼️ One Image, Everywhere: Set a primary thumbnail that automatically syncs to campaign grids, lists, and shortcodes—no more relying on layout order.

📱 Social Sharing Optimized: Easily upload images at the perfect size to ensure your campaigns look stunning and professional when shared on social media.

🔍 SEO & Accessibility Ready: Add custom alt text directly within the builder to improve search rankings and ensure your mission is accessible to every supporter.

Improvement receipts

🗓️ Annual Receipts 2.0: Send Year-End Receipts to Every Donor in Minutes

You can now send annual receipts in minutes with a few clicks to all your donors.

📧 One-Click Bulk Send Wizard that guides you to sending to hundreds of donors simultaneously directly from your WordPress dashboard.

🔍 Smart “Dry Run” Mode: See exactly who will receive a receipt and who will be skipped (and why) before a single email leaves your server.

🛡️ SMTP-Aware & Limit Protection: Charitable now detects your email setup and automatically adjusts batch sizes and pauses for daily limits to ensure your emails land in inboxes.

✅ Complete Audit Trail: Dedicated system log and on the individual donor’s profile, giving you a clear history for every fiscal year.

Stop dreading tax season and start spending that time on your mission. Update to Annual Receipts 2.0 and automate your year-end reporting today.

Addon Donations Improvement

🎈Recurring Donations 2.0: Smarter Automation, Better Recovery, and More Control

We’ve completely rebuilt our Recurring Donations system to help you grow your reliable income stream while giving you (and your donors) more powerful tools than ever before.

What’s New:

🔒 Recurring-Only Campaigns: You can toggle “Recurring Only” mode in the campaign builder to hide the one-time option entirely, ensuring your supporters stay focused on long-term commitment.

📧 Automatic Payment Recovery: Our new Payment Failed Email fires automatically the moment a subscription fails.

🛠️ Self-Service Donor Control:The new Cancel Subscription Button appears directly in the donor dashboard, allowing supporters to pause or end their recurring gifts on their own terms—reducing your admin burden and payment disputes.

📊 Real-Time Revenue Insights: Track your growth, monitor active subscriptions, and see exactly how much predictable support is coming in each month at a glance.

Our new Recurring Donations addon gives you the professional-grade tools you need to grow your mission.