Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

Notable changes to Basicrum Analytics are recorded here.

## [0.1.0] - 2026-09-23
## [0.1.0] - 2026-09-24

### Added

- Illustrated setup instructions for collector details, Magento configuration,
consent integration, and query-string privacy controls.
- The owner-approved root MIT license, matching the existing Composer license
declaration and preserving bundled third-party notices.
- Magento-aware PHPStan level 8, Magento coding standards, precise runtime
Expand Down Expand Up @@ -43,7 +45,7 @@ Notable changes to Basicrum Analytics are recorded here.
page, keeping their settings and guidance immediately visible.
- **Breaking:** normalized the technical Magento module identifier and PHP
namespace to the “Basicrum” spelling: `Basicrum_Analytics` and
`Basicrum\\Analytics`. The lowercase configuration paths remain unchanged.
`Basicrum\Analytics`. The lowercase configuration paths remain unchanged.
This pre-release break was accepted because the extension has no
installations to migrate.
- Removed the explicit Composer package version. Release versions now come
Expand All @@ -69,6 +71,11 @@ Notable changes to Basicrum Analytics are recorded here.

### Fixed

- Remove obsolete consent-cookie cleanup from the readable and minified
loaders. Browser tests verify no cookies before consent and only the `RT`
measurement cookie after initialization.
- Clarify automatic Beacon Endpoint origin registration in storefront CSP and
the cache refresh required after configuration changes.
- The Admin integration test opens Magento's native Basicrum navigation group
before selecting the exact settings link, which is hidden when collapsed.
- Validate package metadata through Composer's validating VCS importer in CI,
Expand Down
73 changes: 53 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,39 @@ headless/PWA storefronts, Varnish, and third-party optimizers are not verified.

## Configuration

### Get your collector details

In the [Basicrum portal](https://app.beta.basicrum.com/), open
**Account > Settings > Sites**. Choose **Add Site** or an existing site, then
copy its **Beacon Endpoint** and **Brum Site ID**. Use your own site's values;
the screenshots show an example.

![Basicrum portal showing the site's Brum Site ID and Beacon Endpoint](docs/images/collector-details.png)

### Enable Basicrum in Magento

Open **Stores > Configuration > Basicrum > Basicrum Analytics**. Settings support
Magento default, website, and store inheritance.

Set **Enable Basicrum** to **Yes**, enter your collector details, and click
**Save Config**. Consent is still required by default.

![Basicrum Analytics enabled in Magento Admin with collector details and monitoring status](docs/images/plugin-settings.png)

Required settings:

- **Enable Basicrum**: new installations default to No.
- **Beacon Endpoint**: a valid HTTP or HTTPS collector URL without embedded
credentials or a fragment. Endpoint query strings remain supported for
compatibility. HTTPS is enforced unless the explicit development exception
is enabled.
credentials or a fragment. Endpoint query strings are supported. HTTPS is
enforced unless the explicit development exception is enabled.
- **Brum Site ID**: a UUIDv4 copied from the Basicrum backoffice.

If Basicrum is disabled or required configuration is missing or invalid, no
monitoring scripts are emitted. The Monitoring Status row explains why
monitoring is inactive. Settings are validated on save and at runtime.

Collection controls:
### Other collection settings

- **Require Consent Before Monitoring** defaults to Yes. Select No only for a
deliberate immediate-loading policy.
- **Strip Query Strings** defaults to No. When enabled, Boomerang replaces
complete query strings in page, navigation, referrer, and resource URLs with
`?qs-redacted` before beacon transmission.
- **Wait After Onload** defaults to No with a zero delay. Its configured delay
is bounded to 30,000 milliseconds.
- **Allow HTTP Beacon Endpoint** defaults to No and is intended only for local
Expand All @@ -101,6 +111,13 @@ action uses `unknown`.

## Consent integration

Under **Visitor Consent**, **Require Consent Before Monitoring** defaults to
**Yes**. Boomerang, measurement cookies, and beacons wait for your consent tool
to allow monitoring on each page. Select **No** only for a deliberate
immediate-loading policy.

![Visitor Consent settings showing required consent and the manual callback API](docs/images/visitor-consent-settings.png)

Basicrum provides manual, page-level callbacks for your consent platform.
It does not display a banner, automatically connect to consent providers,
infer consent from cookies, or persist its own consent decision.
Expand All @@ -123,20 +140,28 @@ if (typeof window.OPT_OUT_BASICRUM_LOADER_WRAPPER === "function") {
```

The consent wrapper is inert until allow. Repeated allow calls load Boomerang
at most once. Denial before the first allow cleans measurement and legacy
consent cookies without preventing a later allow on that page. Withdrawal
during download prevents the arriving bundle from initializing. Withdrawal
after initialization disables further collection, cancels a pending Wait After
Onload timer, and removes `RT`, `BA`, `BRUM_CONSENT`, and `BOOMR_CONSENT`
cookies where JavaScript can reach them. Data already transmitted cannot be
retracted.
at most once. Once initialized, Boomerang uses the first-party `RT` measurement
cookie; Basicrum does not create a consent cookie. Denial before the first allow
does not prevent a later allow on that page. Withdrawal during download prevents
the arriving bundle from initializing. Withdrawal after initialization disables
further collection, cancels a pending Wait After Onload timer, and removes
accessible measurement cookies. Data already transmitted cannot be retracted.

After withdrawal once loading has started, re-grant requires a page reload.
This intentionally prevents a same-page restart from a partially initialized
state. The callbacks are registered by the footer loader; calls made before
registration are not queued. Connect both allow and deny/change events in the
site's consent tool on every page.

## Strip query strings

Under **Privacy**, set **Strip Query Strings** to **Yes** to redact queries
from page, navigation, referrer, and resource URLs. The default is **No**.
For example, `/search?q=boots` becomes `/search?qs-redacted`; URL paths remain.
This does not change query parameters in your configured Beacon Endpoint.

![Privacy settings with Strip Query Strings enabled](docs/images/strip-query-strings-settings.png)

## Caching and CSP

After changing module configuration, clean Magento configuration, layout,
Expand All @@ -145,13 +170,21 @@ new static assets and invalidate any CDN or optimizer cache that can retain old
HTML or JavaScript. Magento's versioned static asset URLs provide browser cache
invalidation only after the deployment/content version changes.

Then visit the storefront, grant consent through your consent tool, and check
the browser's Network panel for a beacon to your endpoint containing your
`brum_site_id`. With consent required, no beacon should appear before opt-in.

The loader and Boomerang are first-party Magento static assets. Inline scripts
use Magento's `SecureHtmlRenderer` for CSP-compatible rendering.

When monitoring configuration is active and valid, Basicrum adds the Beacon
Endpoint origin (scheme, host, and optional port) to storefront `connect-src`
and `img-src` CSP policies. Paths and query strings are excluded. Disabled or
invalid configuration adds no collector origin. No wildcard is added.
When you configure the **Beacon Endpoint** in Magento Admin and enable Basicrum
with valid settings, the module automatically allows the endpoint's domain in
the storefront `connect-src` and `img-src` CSP directives. No separate manual
CSP whitelist entry is needed for that endpoint. The allowed value is its origin
(scheme, host, and optional port), not the full URL: paths and query strings are
excluded. Disabled or invalid configuration adds no collector origin, and no
wildcard is added. Clean the caches described above after saving settings so
cached storefront responses use the updated policy.

If your store uses script delay, combination, or other optimization extensions,
verify consent handling and script loading on staging before deployment.
Expand Down
2 changes: 1 addition & 1 deletion THIRD-PARTY-NOTICES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ The Boomerang copyright notice and BSD license remain applicable to this file.
`64f19d9e5a9fbe580c12c19796e86e3ad0dd17ff`

The consent wrapper adds Basicrum lifecycle, withdrawal, wait cancellation,
and legacy-cookie cleanup around the loader. Those adaptations do not change
and measurement-cookie cleanup around the loader. Those adaptations do not change
the license that applies to the original loader snippet.
Binary file added docs/images/collector-details.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/plugin-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/strip-query-strings-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/visitor-consent-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions tests/js/loaders.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ async function preparePage(page, options = {}) {
if (options.cookies) {
await page.context().addCookies(options.cookies.map((name) => ({
name,
value: "legacy",
value: "existing",
domain: "shop.example.test",
path: "/"
})));
Expand Down Expand Up @@ -139,8 +139,8 @@ for (const consentLoader of [
"consent-boomerang-loader-v1-15.min.js"
]) {
test.describe(`consent wrapper: ${consentLoader}`, () => {
test("stays inert despite a legacy allow cookie", async ({ page }) => {
const harness = await preparePage(page, { cookies: ["BRUM_CONSENT"] });
test("stays inert despite existing measurement cookies", async ({ page }) => {
const harness = await preparePage(page, { cookies: ["RT", "BA"] });
await page.addScriptTag({ path: loaderPath(consentLoader) });
await page.waitForTimeout(200);

Expand Down Expand Up @@ -179,7 +179,7 @@ for (const consentLoader of [
});

test("denial before loading cleans cookies and permits a later allow", async ({ page }) => {
const cookieNames = ["RT", "BA", "BRUM_CONSENT", "BOOMR_CONSENT"];
const cookieNames = ["RT", "BA"];
await preparePage(page, { cookies: cookieNames });
await page.addScriptTag({ path: loaderPath(consentLoader) });
await page.evaluate(() => window.OPT_OUT_BASICRUM_LOADER_WRAPPER());
Expand Down Expand Up @@ -214,7 +214,7 @@ for (const consentLoader of [
});

test("withdrawal after initialization disables collection and clears cookies", async ({ page }) => {
const cookieNames = ["RT", "BA", "BRUM_CONSENT", "BOOMR_CONSENT"];
const cookieNames = ["RT", "BA"];
await preparePage(page, { cookies: cookieNames });
await page.addScriptTag({ path: loaderPath(consentLoader) });
await page.evaluate(() => window.OPT_IN_BASICRUM_LOADER_WRAPPER());
Expand All @@ -233,7 +233,7 @@ for (const consentLoader of [
executions: 1,
disableCalls: 1,
cookies: "",
removals: ["BA", "BOOMR_CONSENT", "BRUM_CONSENT", "RT"]
removals: ["BA", "RT"]
});
});
});
Expand Down
5 changes: 2 additions & 3 deletions tests/js/real-boomerang.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ for (const consentLoader of [
await page.waitForTimeout(300);
expect(gate.boomerangRequests()).toBe(0);
expect(gate.beaconRequests()).toBe(0);
expect((await context.cookies(shopUrl)).some((cookie) => ["RT", "BA"].includes(cookie.name))).toBe(false);
expect(await context.cookies(shopUrl)).toEqual([]);

await page.evaluate(() => {
window.OPT_IN_BASICRUM_LOADER_WRAPPER();
Expand All @@ -194,8 +194,7 @@ for (const consentLoader of [
const parameters = requestParameters(gate.beaconRequestData()[0]);
expect(parameters.get("p_gen")).toBe("mage2");
expect(parameters.get("brum_site_id")).toBe(siteId);
expect((await context.cookies(shopUrl)).some((cookie) => cookie.name === "RT")).toBe(true);
expect((await context.cookies(shopUrl)).some((cookie) => cookie.name === "BRUM_CONSENT")).toBe(false);
expect((await context.cookies(shopUrl)).map((cookie) => cookie.name).sort()).toEqual(["RT"]);
});

test("denial before loading remains eligible for a later allow", async ({ page }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@
/* END BASICRUM STANDARD LOADER */
};

// Remove cookies created by older Basicrum consent loaders and Boomerang.
// Remove Boomerang measurement cookies.
function removeCookie(name) {
var hostname = mainWin.location && mainWin.location.hostname;
var cookie = name + "=; path=/; max-age=0; SameSite=Strict";
Expand Down Expand Up @@ -248,14 +248,10 @@
if (mainWin.BOOMR.utils && typeof mainWin.BOOMR.utils.removeCookie === "function") {
mainWin.BOOMR.utils.removeCookie("RT");
mainWin.BOOMR.utils.removeCookie("BA");
mainWin.BOOMR.utils.removeCookie("BRUM_CONSENT");
mainWin.BOOMR.utils.removeCookie("BOOMR_CONSENT");
}
}

removeCookie("RT");
removeCookie("BA");
removeCookie("BRUM_CONSENT");
removeCookie("BOOMR_CONSENT");
};
})(window);

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading