How to add Web Experiment to a WordPress site

Configure a WordPress CTA copy test with Amplitude Web Experiment. Preview variants and check impressions and accepted form conversions.

  • WordPress 6.3+
  • Custom plugin
  • Browser SDK 2
  • CDN
  • 25 min

Chris Tam · Last updated 16 October 2026

WordPress owns the page template and published content. Web Experiment lets you test a change to that page and measure an outcome from the same visitor's activity.

In this tutorial, I'll target Pricing, select its CTA with a stable attribute, and preview a copy test against the form-acceptance event.

What you'll build

A Pricing CTA experiment with control and treatment previews and Demo Form Accepted selected as its primary conversion metric.

Prerequisites

  • A staging WordPress site with permission to upload a custom plugin and edit wp-config.php. This tutorial uses a plugin you control. On managed hosting, confirm that your plan permits those changes.
  • WordPress 6.3 or later and PHP 7.4 or later, plus a theme that calls wp_head() and wp_footer(). The executable example was tested on WordPress 6.9.10 and PHP 8.3.33.
  • An Amplitude project API key: Settings > Projects > your project > General > Manage next to API Key. Managers and Admins can view it. The browser key is public and limited to the minimum scope needed for ingestion. Keep secret keys out of this plugin.
  • The shared WordPress plugin, Pricing page, shortcode form, and Demo Form Accepted event from the WordPress product analytics tutorial.
  • Access to create a Web Experiment in the same Amplitude test project.

A free Amplitude account covers this example within its product limits. Sign up for free to get your project API key.

The Unified Script reference includes Web Experiment in the project-specific .js loader. Keep that installation path. If Web Experiment needs consent gating, add experiment-consent.js below; the shared PHP file inserts it before the existing loader.

wp-content/plugins/amplitude-build/experiment-consent.js
// wp-content/plugins/amplitude-build/experiment-consent.js
// This gates Web Experiment only; wire your CMP's actual decision callback.
window.experimentConfig = {
  ...window.experimentConfig,
  consentOptions: { consentRequired: true, consentStatus: 'pending' }
};

Wire your consent platform's actual callback after the script is available:

Consent platform callback after the Web Experiment script loads
// Consent platform callback after the Web Experiment script loads
window.webExperiment?.setConsentStatus('granted'); // Use denied for refusal or withdrawal.

If the decision is already known, initialize consentStatus with it. Retain callbacks that arrive before the script is available and apply them after load; optional chaining alone drops an early call. Pending consent can apply variants in memory while buffering impressions. A documented refusal-marker cookie can survive denial. This gate covers Web Experiment; if analytics or replay must also wait, defer the entire shared integration through your consent platform.

2. Give the CTA a stable target

On Pricing, preserve this Custom HTML block and its analytics and guide attributes. Target the nested text span so the link destination and parent attributes remain intact.

Pricing page: Custom HTML block
<!-- Pricing page: Custom HTML block -->
<a href="#demo" data-analytics="pricing-cta" data-experiment="pricing-cta" data-guide="pricing-help">
  <span>Request a demo</span>
</a>
Visual Editor selector
/* Visual Editor selector */
[data-experiment="pricing-cta"] span

In the element drawer, click the selector edit icon, enter the attribute selector, and click the icon again to commit it before editing Copy. After saving the variant, re-open its change history and verify this selector persisted. A correct-looking preview can still use a generic span selector that matches unrelated text after a page edit.

3. Create the experiment and primary metric

In Experiments > Create Experiment > Web Experiment, choose the test project and public Pricing URL. Choose Element Changes. Configure a text action on the stable CTA selector for each variant: control Request a demo, treatment See the product with an expert. Scope the experiment's Pages to Pricing.

For control, make the original copy an explicit action. In the unpublished Visual Editor, change Copy temporarily, then restore Request a demo before Apply & Exit. Check Change History for the restored text and committed selector. An empty control action did not emit an impression in my WordPress preview; the explicit action did. The temporary text must never be the saved experiment configuration.

Experiment configuration
# Experiment configuration
Name: WordPress pricing CTA QA
Primary conversion event: Demo Form Accepted
Control: Request a demo
Treatment: See the product with an expert

In Metrics, choose Create a custom metric, count unique users performing Demo Form Accepted, select the event with Add Event, and save it as the primary metric. Save the experiment configuration. Keep ordinary rollout at 0% during preview QA.

4. Preview both variants and check instrumentation

Use Test & Preview to open each variant. It does not launch the experiment for ordinary visitors. Allow up to 60 seconds for caches after changes. Verify the text, #demo destination, accepted server response, and one conversion.

Browser Console after one accepted synthetic form
// Browser Console after one accepted synthetic form
window.amplitude.flush();
window.amplitude.getDeviceId();

Inspect impressions separately from rendered copy. Browser-side events use $impression; ingestion transforms them to [Experiment] Impression with flag and variant properties. Confirm the required impressions for both variants before relying on experiment analysis. If a variant renders without its expected impression, keep the experiment unlaunched and resolve tracking. Do not synthesize an impression to make a test pass. Preview is not a winning-result calculation.

MCP: Ask your coding agent to inspect the project's event taxonomy with the Amplitude MCP server before adding events. Reuse existing names when they describe the same action.

Verify it worked

  1. WordPress output: Open the public staging page while logged out. Check that the project loader appears once and its inline initialization follows it. After deployment or configuration changes, purge the relevant page and CDN caches.
  2. Network: Confirm an event POST receives HTTP 200 from api2.amplitude.com for US projects or api.eu.amplitude.com for EU projects. Large batches can be compressed; use this check for delivery status.
  3. Instrumentation Explorer: Inspect event names, properties, counts, and device_id in the Chrome extension. Compare one action with one expected custom event.
  4. User Profiles: Search that device ID in Amplitude and inspect its event stream. The docs describe a delay of ten seconds to one minute. Data > Sources > Ingestion Debugger shows request and event counts, rather than individual event payloads.

Check both rendered variants, their required ingested impressions, and confirmed form conversions. Keep ordinary rollout at 0% until those checks and targeting review pass.

Troubleshooting

The plugin is active but no SDK loads

Check that AMP_BUILD_API_KEY is defined before wp-settings.php, then inspect the public page source. This plugin uses the front-end enqueue hook, so its SDK is absent from the WordPress login and administration pages.

The script order differs from the example

Check caching and script-optimization exclusions for amp-build-sdk and amp-build-engagement. The project loader and inline initialization must remain together. Check for an earlier installation in a theme, tag manager, or snippet plugin.

Requests are blocked

Check the key, region, browser extensions, and Console. Follow the relevant SDK's CSP and endpoint guidance while preserving your site's security policy.

Autocapture settings differ from the file

Review Data > Settings > Autocapture. When remote configuration is enabled, remote values take precedence for the features they specify.

FAQ

Should I add another experiment loader?

This tutorial's project-specific Unified Script already includes Web Experiment. Keep one integration path.

Does previewing the treatment launch the experiment?

Test & Preview applies the chosen variant to its preview visitor. Starting the experiment for its ordinary audience is a separate action.

Full code reference

Unchanged from earlier pages; keep your versions: amplitude-build.php, analytics.js, demo.php, events.js, engagement.php. Merge the changes into existing files; preserve sibling additions named in the comments.

wp-content/plugins/amplitude-build/experiment-consent.js
// wp-content/plugins/amplitude-build/experiment-consent.js
// This gates Web Experiment only; wire your CMP's actual decision callback.
window.experimentConfig = {
  ...window.experimentConfig,
  consentOptions: { consentRequired: true, consentStatus: 'pending' }
};

Hand it to your agent

Point your agent at https://amplitude.com/build/wordpress-web-experiment.

Agent prompt
Agent task: WordPress Web Experiment.
Preserve the shared loader, analytics, replay privacy, guides, and conversion form. Add Web Experiment consent configuration only where required and connect the actual CMP callback. Create a dedicated Pricing test, use [data-experiment="pricing-cta"] span, and verify the persisted selector after saving. Save explicit text actions for both variants, including original control copy. Keep rollout zero, preview both variants, inspect transformed impressions and Demo Form Accepted, and report missing impressions as unresolved.

What this unlocks

Product analytics measures the accepted-form outcome when Demo Form Accepted is installed.

Session replay shows the interaction around the test form after capture and masking are verified.

Web Experiment can use Demo Form Accepted as a conversion metric.

Guides and surveys can ask a visitor what they need on Pricing after targeting is configured.

Next steps

Add Amplitude to your WordPress site

Start with one shared plugin and follow the tutorials for each product.