From fe27c89b5fe219f8e6af21a96b849224536d6fe4 Mon Sep 17 00:00:00 2001
From: Akanksha Trehun
Date: Wed, 2 Sep 2026 14:20:23 +0530
Subject: [PATCH 1/2] feat: wire up Datadog RUM for client-side monitoring
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Adds @datadog/browser-rum + @datadog/browser-rum-react, initialized via a
client-only DatadogInit component mounted in the root layout. Session
replay is explicitly disabled (sessionReplaySampleRate: 0) since it would
visually record the editor UI, which cuts against Reframe's "100% private"
positioning — metrics/errors only. applicationId/clientToken are read from
NEXT_PUBLIC_* env vars (documented in .env.example), never hardcoded.
Not pushed: src/app/privacy/page.tsx currently states Reframe "does not
embed analytics SDKs" and collects "no analytics, telemetry ... of any
kind" — directly contradicted by this change. Needs a wording pass before
this goes near main.
Co-Authored-By: Claude Sonnet 5
Claude-Session: https://claude.ai/code/session_01L5gqyU5QKQtLAza6hL6dXv
---
.env.example | 14 +++++++++++++
bun.lock | 34 +++++++++++++-------------------
package.json | 2 ++
src/app/layout.tsx | 3 ++-
src/components/DatadogInit.tsx | 36 ++++++++++++++++++++++++++++++++++
5 files changed, 68 insertions(+), 21 deletions(-)
create mode 100644 .env.example
create mode 100644 src/components/DatadogInit.tsx
diff --git a/.env.example b/.env.example
new file mode 100644
index 00000000..8eef9073
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,14 @@
+# Datadog RUM (client-side monitoring).
+#
+# Both values are public-facing client identifiers, not secrets — Datadog
+# designs them to ship inside the browser bundle — but they still shouldn't
+# be hardcoded in source, since they differ per Datadog org.
+#
+# Get these from Organization Settings > RUM Applications in Datadog after
+# creating the "reframe" RUM application (app.datadoghq.com).
+#
+# NEXT_PUBLIC_* vars are inlined at build time (this is a static export),
+# so set them in Vercel/Netlify's build environment settings too — not just
+# a local .env.local.
+NEXT_PUBLIC_DATADOG_APPLICATION_ID=
+NEXT_PUBLIC_DATADOG_CLIENT_TOKEN=
diff --git a/bun.lock b/bun.lock
index 4d28daf4..52c2ac3f 100644
--- a/bun.lock
+++ b/bun.lock
@@ -5,6 +5,8 @@
"": {
"name": "reframe",
"dependencies": {
+ "@datadog/browser-rum": "^7.10.0",
+ "@datadog/browser-rum-react": "^7.10.0",
"@ffmpeg/ffmpeg": "^0.12.10",
"@ffmpeg/util": "^0.12.2",
"clsx": "^2.1.1",
@@ -277,6 +279,16 @@
"@csstools/css-tokenizer": ["@csstools/css-tokenizer@4.0.0", "", {}, "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA=="],
+ "@datadog/browser-core": ["@datadog/browser-core@7.10.0", "", { "dependencies": { "@datadog/js-core": "0.0.11" } }, "sha512-j61ey06o6KNKucMcthtbIi7bvo0Mbl1OjBVW6LmmWiInin9v91d53w6UNBCmf4xY6MsZ+vpNg3JjGKqLW2haOA=="],
+
+ "@datadog/browser-rum": ["@datadog/browser-rum@7.10.0", "", { "dependencies": { "@datadog/browser-core": "7.10.0", "@datadog/browser-rum-core": "7.10.0", "@datadog/js-core": "0.0.11" }, "peerDependencies": { "@datadog/browser-logs": "7.10.0" }, "optionalPeers": ["@datadog/browser-logs"] }, "sha512-W3p9miiDMmXlq4dKcI9SCf0zPH7ifKD5EQdB9ISqBkIylD4SftKjT4gNFWD+cqPdO+XDjCUxtZkKUxR/WMp3XQ=="],
+
+ "@datadog/browser-rum-core": ["@datadog/browser-rum-core@7.10.0", "", { "dependencies": { "@datadog/browser-core": "7.10.0", "@datadog/js-core": "0.0.11" } }, "sha512-B3+we2lLQQx90M7rgAroz32u4HDyPYLX7BOLw4zWc/JX0TQwPpuwWyhyyUruWT0/kFQfmCZpUFc6dJPL/A8AvQ=="],
+
+ "@datadog/browser-rum-react": ["@datadog/browser-rum-react@7.10.0", "", { "dependencies": { "@datadog/browser-core": "7.10.0", "@datadog/browser-rum-core": "7.10.0", "@datadog/js-core": "0.0.11" }, "peerDependencies": { "@datadog/browser-rum": "*", "@datadog/browser-rum-slim": "*", "@tanstack/react-router": ">=1.64.0 <2", "react": "18 || 19", "react-router": "6 || 7 || 8", "react-router-dom": "6 || 7" }, "optionalPeers": ["@datadog/browser-rum", "@datadog/browser-rum-slim", "@tanstack/react-router", "react", "react-router", "react-router-dom"] }, "sha512-7pD6/GZRMopQRHtm57kc9L4O4NRMlfF48cqaFBCk9HDq1ufhAMdahjr8bT7rQzuzFZsRK/KmhixF74hZ6z9Gzg=="],
+
+ "@datadog/js-core": ["@datadog/js-core@0.0.11", "", {}, "sha512-iuD5d3poicqdP6u6lTgRQGNnK31pAk9v4E1xCEE6JgUo4xknbvb16DSvJrPdPI8+hido1/bZei66xFNcepLjCA=="],
+
"@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="],
@@ -613,7 +625,7 @@
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
- "@testing-library/dom": ["@testing-library/dom@9.3.4", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.1.3", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" } }, "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ=="],
+ "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="],
"@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="],
@@ -999,8 +1011,6 @@
"deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
- "deep-equal": ["deep-equal@2.2.3", "", { "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.5", "es-get-iterator": "^1.1.3", "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "isarray": "^2.0.5", "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", "which-typed-array": "^1.1.13" } }, "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA=="],
-
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
@@ -1073,8 +1083,6 @@
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
- "es-get-iterator": ["es-get-iterator@1.1.3", "", { "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", "has-symbols": "^1.0.3", "is-arguments": "^1.1.1", "is-map": "^2.0.2", "is-set": "^2.0.2", "is-string": "^1.0.7", "isarray": "^2.0.5", "stop-iteration-iterator": "^1.0.0" } }, "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw=="],
-
"es-iterator-helpers": ["es-iterator-helpers@1.3.2", "", { "dependencies": { "call-bind": "^1.0.9", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.2", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.3.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", "math-intrinsics": "^1.1.0" } }, "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw=="],
"es-module-lexer": ["es-module-lexer@2.1.0", "", {}, "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ=="],
@@ -2013,7 +2021,7 @@
"@testing-library/dom/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
- "@testing-library/dom/aria-query": ["aria-query@5.1.3", "", { "dependencies": { "deep-equal": "^2.0.5" } }, "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ=="],
+ "@testing-library/dom/aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="],
"@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
@@ -2065,16 +2073,12 @@
"create-hmac/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
- "deep-equal/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
-
"diffie-hellman/bn.js": ["bn.js@4.12.5", "", {}, "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ=="],
"dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="],
"elliptic/bn.js": ["bn.js@4.12.5", "", {}, "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ=="],
- "es-get-iterator/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
-
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-import-resolver-node/resolve": ["resolve@2.0.0-next.7", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.2", "node-exports-info": "^1.6.0", "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ=="],
@@ -2181,8 +2185,6 @@
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
- "storybook/@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="],
-
"stream-browserify/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
"stream-http/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
@@ -2243,12 +2245,6 @@
"schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
- "storybook/@testing-library/dom/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
-
- "storybook/@testing-library/dom/aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="],
-
- "storybook/@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
-
"vitest/@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
"webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="],
@@ -2259,8 +2255,6 @@
"pkg-dir/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
- "storybook/@testing-library/dom/@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
-
"@storybook/react-docgen-typescript-plugin/find-cache-dir/pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
"pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
diff --git a/package.json b/package.json
index 622e1357..93d03dde 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,8 @@
"chromatic": "chromatic --exit-zero-on-changes"
},
"dependencies": {
+ "@datadog/browser-rum": "^7.10.0",
+ "@datadog/browser-rum-react": "^7.10.0",
"@ffmpeg/ffmpeg": "^0.12.10",
"@ffmpeg/util": "^0.12.2",
"clsx": "^2.1.1",
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index f16cedb2..46651aba 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { Bebas_Neue, Syne, DM_Sans, Inter, Roboto, Poppins, Montserrat } from "next/font/google";
import ErrorBoundary from "@/components/ErrorBoundary";
import "./globals.css";
+import DatadogInit from "@/components/DatadogInit";
import { ThemeProvider } from "@/components/ThemeProvider";
import { ThemeToggle } from "@/components/ThemeToggle";
import ScrollToTop from "@/components/ScrollToTop";
@@ -68,7 +69,7 @@ export default function RootLayout({
-
+
diff --git a/src/components/DatadogInit.tsx b/src/components/DatadogInit.tsx
new file mode 100644
index 00000000..4d8ed057
--- /dev/null
+++ b/src/components/DatadogInit.tsx
@@ -0,0 +1,36 @@
+"use client";
+
+import { useEffect } from "react";
+import { datadogRum } from "@datadog/browser-rum";
+import { reactPlugin } from "@datadog/browser-rum-react";
+
+export default function DatadogInit() {
+ useEffect(() => {
+ const applicationId = process.env.NEXT_PUBLIC_DATADOG_APPLICATION_ID;
+ const clientToken = process.env.NEXT_PUBLIC_DATADOG_CLIENT_TOKEN;
+
+ if (!applicationId || !clientToken) {
+ return;
+ }
+
+ datadogRum.init({
+ applicationId,
+ clientToken,
+ site: "datadoghq.com",
+ service: "reframe",
+ env: "production",
+ version: "0.1.0",
+ sessionSampleRate: 100,
+ // Reframe advertises itself as 100% private client-side video editing —
+ // session replay would visually record the editor UI, which cuts
+ // against that claim. Metrics/errors only.
+ sessionReplaySampleRate: 0,
+ plugins: [reactPlugin()],
+ trackUserInteractions: true,
+ trackResources: true,
+ trackLongTasks: true,
+ });
+ }, []);
+
+ return null;
+}
From 308362cd53a723ed6754663be00cdef61528a65a Mon Sep 17 00:00:00 2001
From: Akanksha Trehun
Date: Wed, 2 Sep 2026 14:57:58 +0530
Subject: [PATCH 2/2] docs: disclose Datadog RUM telemetry in privacy policy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Sections 1 and 3 previously stated Reframe embeds no analytics SDKs and
collects no telemetry of any kind — false as of the Datadog RUM
integration. Rewrites both to accurately describe what's actually
collected (anonymous page views, load performance, JS errors), explicitly
states session replay is off, and clarifies telemetry can never include
video/audio content since that data never leaves the browser regardless.
Section 8's "absence of telemetry" claim updated to match.
Co-Authored-By: Claude Sonnet 5
Claude-Session: https://claude.ai/code/session_01L5gqyU5QKQtLAza6hL6dXv
---
src/app/privacy/page.tsx | 44 ++++++++++++++++++++++++++++++++--------
1 file changed, 35 insertions(+), 9 deletions(-)
diff --git a/src/app/privacy/page.tsx b/src/app/privacy/page.tsx
index dbe1e3fb..252c78aa 100644
--- a/src/app/privacy/page.tsx
+++ b/src/app/privacy/page.tsx
@@ -87,8 +87,20 @@ export default function PrivacyPage() {
derived content ever leaves your browser.
- Reframe does not embed analytics SDKs, advertising scripts, or
- background data collection mechanisms of any kind.
+ Reframe embeds Datadog Real User Monitoring (RUM) to collect
+ anonymous performance and error metrics — page views, load
+ times, and JavaScript errors. Session replay is disabled.
+ This telemetry never includes your video files, audio,
+ filenames, exported content, or any other media you work
+ with in the app. See{" "}
+
+ Telemetry & Diagnostics
+ {" "}
+ below for details. Reframe does not embed advertising
+ scripts.
@@ -107,13 +119,27 @@ export default function PrivacyPage() {
not controlled by Reframe.
-
+
3. Telemetry & Diagnostics
- Reframe does not collect analytics, telemetry, crash reports, or
- usage tracking of any kind. No diagnostic data is transmitted to
- developers or third parties.
+ Reframe uses Datadog RUM to collect anonymous, aggregate
+ telemetry: page views, load performance, and JavaScript
+ errors. This helps us catch bugs and performance regressions
+ across browsers we don't personally test on.
+
+
+ Session replay is explicitly disabled — Datadog never
+ records or reconstructs what the editor looked like during
+ your session. Telemetry is limited to metrics and error
+ events; it does not and cannot include your video or audio
+ files, filenames, export settings, or any content you
+ create or edit in the app, since that data never leaves
+ your browser in the first place (see Data Collection
+ above).
@@ -172,9 +198,9 @@ export default function PrivacyPage() {
Reframe is open source and publicly verifiable. The entire
- codebase, including processing logic and dependency usage, can
- be audited on GitHub to confirm its local-first architecture and
- absence of telemetry or data collection.
+ codebase, including processing logic, dependency usage, and
+ exactly what telemetry is collected and how, can be audited
+ on GitHub to confirm its local-first architecture.