analytics: add Marlin SDK and migrate dropdown Heap markers

Introduces @docker/marlin-sdk-web-public for first-party pageview and
click analytics, bundled into scripts.js via Hugo's existing js.Build
pipeline. Config is emitted to window.__marlinConfig from head.html and
gated to prod/staging only.

Renames data-heap-id attributes on the markdown-dropdown buttons to
marlin-action so they are picked up by the SDK's auto-click tracking.

TODO: replace the REPLACE-ME endpoint placeholders in hugo.yaml with
the canonical Marlin ingestion URLs from the data-platform team.

TODO: heap.track() calls in youtube-script.html are left in place —
the public SDK exposes no equivalent track() method, so video
play/pause events cannot be migrated yet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
This commit is contained in:
David KarlssonandClaude Opus 4.7 committed 2026-05-22 13:40:16 +02:00
1 parent 807a8ec42a
commit a6c2209c7f
6 files changed
+115 -4

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
import { Marlin, Environment } from "@docker/marlin-sdk-web-public";
const config = window.__marlinConfig;
if (config && config.apiKey && config.endpoint) {
try {
window.marlin = new Marlin({
endpoint: config.endpoint,
apiKey: config.apiKey,
site: "docs",
environment:
config.environment === "staging"
? Environment.STAGING
: Environment.PROD,
});
} catch (err) {
console.warn("Marlin SDK init failed:", err);
}
}
+8
View File
@@ -142,6 +142,14 @@ params:
google: GTM-WL2QLG5
onetrust: 65425fb0-7b36-4317-9f10-7b3e08039af0
vwo: 723167
marlin:
# Public-write API keys for the Marlin analytics SDK.
apiKey:
prod: mrl_2nuEKUo5bzRv8GcDKeYjij4J4U--OLdN
stage: mrl_W14SGEQ7nYmBsAyjZPyOM-nlgE53E-vX
endpoint:
prod: https://marlin-2.docker.com
stage: https://marlin-2-stage.docker.com
# Docs repository URL
repo: https://github.com/docker/docs
+23
View File
@@ -67,6 +67,29 @@
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
{{ end }}
{{- with site.Params.analytics.marlin -}}
{{- $apiKey := "" -}}
{{- $endpoint := "" -}}
{{- $env := "" -}}
{{- if hugo.IsProduction -}}
{{- $apiKey = .apiKey.prod -}}
{{- $endpoint = .endpoint.prod -}}
{{- $env = "prod" -}}
{{- else if eq hugo.Environment "staging" -}}
{{- $apiKey = .apiKey.stage -}}
{{- $endpoint = .endpoint.stage -}}
{{- $env = "staging" -}}
{{- end -}}
{{- if and $apiKey $endpoint -}}
<script>
window.__marlinConfig = {
apiKey: {{ $apiKey | jsonify }},
endpoint: {{ $endpoint | jsonify }},
environment: {{ $env | jsonify }}
};
</script>
{{- end -}}
{{- end -}}
{{/* preload Roboto Flex as it's a critical font: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload */}}
<link
href="/assets/fonts/RobotoFlex.woff2"
+4 -4
View File
@@ -2,7 +2,7 @@
<div class="flex flex-wrap items-center gap-x-6 gap-y-2 text-sm">
<button
onclick="askGordon()"
data-heap-id="ask-gordon-button"
marlin-action="ask-gordon-button"
class="inline-flex cursor-pointer items-center gap-1.5 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100"
>
<span class="icon-svg icon-sm -translate-y-px">
@@ -13,7 +13,7 @@
<button
onclick="copyMarkdown()"
data-heap-id="copy-markdown-button"
marlin-action="copy-markdown-button"
class="inline-flex cursor-pointer items-center gap-1.5 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100"
>
<span class="icon-svg icon-sm">
@@ -27,7 +27,7 @@
<button
onclick="viewPlainText()"
data-heap-id="view-markdown-button"
marlin-action="view-markdown-button"
class="inline-flex cursor-pointer items-center gap-1.5 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100"
>
<span class="icon-svg icon-sm">
@@ -51,7 +51,7 @@
.then((text) => {
navigator.clipboard.writeText(text).then(() => {
const button = document.querySelector(
'[data-heap-id="copy-markdown-button"]',
'[marlin-action="copy-markdown-button"]',
);
if (!button) return;
+60
View File
@@ -12,6 +12,7 @@
"@alpinejs/collapse": "3.15.8",
"@alpinejs/focus": "3.15.8",
"@alpinejs/persist": "3.15.8",
"@docker/marlin-sdk-web-public": "0.2.0",
"@floating-ui/dom": "1.7.6",
"@tailwindcss/cli": "4.2.1",
"@tailwindcss/typography": "0.5.19",
@@ -50,6 +51,52 @@
"integrity": "sha512-xKJk0aa5p0QAquP9ivEuLnpzuBC2MyoWmiMRVzWiTR9/VLnbVgFM+6dE/D+NvfKOzhTSeht6FkYqOi/C27LBTg==",
"license": "MIT"
},
"node_modules/@bufbuild/cel": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@bufbuild/cel/-/cel-0.4.0.tgz",
"integrity": "sha512-CdW/JgiTJCYXqnwuaJRo7NcoYhR37AaF58MMiog0/t8nudn86ZyLXYaA1f2yGhm2U17h8pKGZNksTHVSTcpmAw==",
"dependencies": {
"@bufbuild/cel-spec": "0.4.0"
},
"peerDependencies": {
"@bufbuild/protobuf": "^2.6.2"
}
},
"node_modules/@bufbuild/cel-spec": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@bufbuild/cel-spec/-/cel-spec-0.4.0.tgz",
"integrity": "sha512-dUS6f2fNt6KEumsYGE7YFxERZE5ZuyME1hQmGjtO8tkZhR6ow6/ne3v4Gik9cfdb9lSLK3AJ+vDxCdGWmDbWvA==",
"peerDependencies": {
"@bufbuild/protobuf": "^2.6.2"
}
},
"node_modules/@bufbuild/protobuf": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz",
"integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ=="
},
"node_modules/@bufbuild/protovalidate": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@bufbuild/protovalidate/-/protovalidate-1.1.1.tgz",
"integrity": "sha512-sE6CojU25nfeb1w88Sm+jRnmk4GvQTeEZvLDHHDPvIHbj2NsDJWFAUJdJr+RcuMnjdWmbur+rAS38VuEK/XviQ==",
"dependencies": {
"@bufbuild/cel": "0.4.0"
},
"peerDependencies": {
"@bufbuild/protobuf": "^2.8.0"
}
},
"node_modules/@docker/marlin-sdk-web-public": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@docker/marlin-sdk-web-public/-/marlin-sdk-web-public-0.2.0.tgz",
"integrity": "sha512-muk4faf3+aE9HbzGWpZCCkOmsve0BgEktQrQmWyoE05JZR8LvPEoarsiAeIMqwk9tPWMJ+0tyIlARd+41Ybw4g==",
"dependencies": {
"@bufbuild/protobuf": "2.11.0",
"@bufbuild/protovalidate": "1.1.1",
"idb": "8.0.3",
"uuidv7": "1.1.0"
}
},
"node_modules/@floating-ui/core": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
@@ -958,6 +1005,11 @@
"node": ">=12.0.0"
}
},
"node_modules/idb": {
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/idb/-/idb-8.0.3.tgz",
"integrity": "sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg=="
},
"node_modules/is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
@@ -2192,6 +2244,14 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/uuidv7": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/uuidv7/-/uuidv7-1.1.0.tgz",
"integrity": "sha512-2VNnOC0+XQlwogChUDzy6pe8GQEys9QFZBGOh54l6qVfwoCUwwRvk7rDTgaIsRgsF5GFa5oiNg8LqXE3jofBBg==",
"bin": {
"uuidv7": "cli.js"
}
}
}
}
+1
View File
@@ -17,6 +17,7 @@
"@alpinejs/collapse": "3.15.8",
"@alpinejs/focus": "3.15.8",
"@alpinejs/persist": "3.15.8",
"@docker/marlin-sdk-web-public": "0.2.0",
"@floating-ui/dom": "1.7.6",
"@tailwindcss/cli": "4.2.1",
"@tailwindcss/typography": "0.5.19",