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/hydrogen3.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
| Cookie | Change in 4.0 |
|---|---|
__pack | Stores the visitor id only with analytics consent. Without it, the cookie still holds preview settings and the id changes on every request. |
__pack_test | Holds one entry per test the visitor is in, instead of one test. Older cookies are converted in place. |
__pack_exposed | Replaces exposedTest. Records exposures already reported, limited in size so it can't exceed the browser's cookie limit. |
__pack_user_consent | Now 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.