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.