Upgrading to @pack/hydrogen 4.0

@pack/hydrogen 4.0 changes how visitors are placed into tests, adds personalization, and makes Pack honor visitor consent. Most storefronts need only a small change to how they read the test a visitor is in. This guide covers what changes and what to update.

Before you upgrade

Upgrade between tests, not during one. Running several tests at once was already possible, but earlier versions served each visitor only one of them. On 4.0 a visitor joins every test they are eligible for. On a store running two or more tests, upgrading therefore changes who is in each test straight away, and visitors from before and after the upgrade are no longer comparable. Existing assignments are kept, but the result of a test already in flight is affected.

The best time to upgrade is when no test is running, or right after one ends.

Install

Update both Pack packages together:

package.json

{
  "dependencies": {
    "@pack/hydrogen": "^4.0.0",
    "@pack/react": "^4.6.0"
  }
}
  • React Router 7 is required, as it already was for @pack/hydrogen 3.x.
  • 4.0 adds a dependency on graphql. Hydrogen storefronts already install it for codegen, so most resolve it without changes.

What changes for your visitors

  • Every eligible test, not one. A visitor is placed into every running test they qualify for. Previously each visitor got one test at random, so with several tests running each reached only part of its audience.
  • Tests apply per query. Site settings and page content are fetched separately, so a navigation test and a product page test can both apply on the same page.
  • Two tests never change the same content at once. When they would, the visitor sees only one of them there. Which one is fixed per visitor, and across all visitors the traffic splits between the tests.

Theme changes

1. Expose Pack's data from the root loader

The hooks below, and PackTestProvider's consent default, read Pack's data from your root loader. If your root loader does not already spread getPackContextData(), add it:

app/root.tsx

export async function loader({context}: LoaderFunctionArgs) {
  // ...your existing data
  return {
    // ...
    ...context.pack.getPackContextData(),
  };
}

2. Name the test you mean

useAbTest() with no argument returns the visitor's oldest test. When a visitor could only be in one test that was always the test on the page. Now it may not be, so name the test:

Before

const test = useAbTest();

return test?.testVariant.handle === 'variant-b' ? <NewHero /> : <Hero />;

After

const test = useAbTest('homepage-hero');

return test?.testVariant.handle === 'variant-b' ? <NewHero /> : <Hero />;

This matters most for variant handles. New tests name their variants control and variant-b, so without a test handle you can read one test's variant-b while the visitor is in control of the test you are branching on. useAbTest, useAbTestId, useAbTestHandle, useAbTestVariantId and useAbTestVariantHandle all take the test handle. See the A/B Testing API.

In development, Pack logs a warning when a visitor is in more than one test and a hook is called without a handle.

3. Check PackTestProvider's consent

PackTestProvider only reports exposures while hasUserConsent is true.

  • If you pass hasUserConsent, nothing changes.
  • If you do not, it now follows the visitor's analytics consent as Pack sees it. Previously it defaulted to false, which held every exposure, so a storefront that never passed it reported no exposures. After upgrading, those exposures start being reported.

See Consent Management.

4. Signed-in audiences

If you target signed-in customers, pass getCustomerContext to createPackClient. See Targeting signed-in customers.

5. Consent

Pack now honors visitor consent. Stores using Shopify's privacy banner get this with no code: PackProvider passes the visitor's answer to Pack. Stores using another consent tool, and stores that call usePackCookies(), should follow Consent Management. usePackCookies() still works but is deprecated.

Cookies that change

CookieChange in 4.0
__packStores the visitor id only with analytics consent. Without it, the cookie still holds preview settings and the id changes on every request.
__pack_testHolds one entry per test the visitor is in, instead of one test. Older cookies are converted in place.
__pack_exposedReplaces exposedTest. Records exposures already reported, limited in size so it can't exceed the browser's cookie limit.
__pack_user_consentNow set by the server, with one answer per purpose. The old "true" / "false" values are still read.

Checking the upgrade

  • In the browser console, window.packDebug.getTestInfos() lists every test the visitor is in, oldest first.
  • A visitor who qualifies for two tests that change different content should now see both.
  • Watch the development console for warnings about hooks called without a test handle.

Was this page helpful?