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
14 changes: 14 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -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=
456 changes: 234 additions & 222 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"security": "npm install --package-lock-only --ignore-scripts && snyk test --severity-threshold=high --file=package-lock.json"
},
"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",
Expand Down
3 changes: 2 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -68,7 +69,7 @@ export default function RootLayout({
<link rel="dns-prefetch" href="https://cdn.jsdelivr.net" />
</head>
<body className="min-h-screen bg-[var(--bg)] text-[var(--text)] antialiased">

<DatadogInit />
<a href="#main-content"
className="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-50 focus:rounded-[var(--radius)] focus:border focus:border-[var(--border)] focus:bg-[var(--surface)] focus:px-4 focus:py-2 focus:text-[var(--text)]"
>
Expand Down
44 changes: 35 additions & 9 deletions src/app/privacy/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,20 @@ export default function PrivacyPage() {
derived content ever leaves your browser.
</p>
<p className="text-[var(--muted)] mt-4">
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{" "}
<a
href="#telemetry"
className="text-[var(--accent)] hover:underline"
>
Telemetry &amp; Diagnostics
</a>{" "}
below for details. Reframe does not embed advertising
scripts.
</p>

<h2 className="text-2xl font-semibold mt-12 mb-6 text-[var(--text)]">
Expand All @@ -107,13 +119,27 @@ export default function PrivacyPage() {
not controlled by Reframe.
</p>

<h2 className="text-2xl font-semibold mt-12 mb-6 text-[var(--text)]">
<h2
id="telemetry"
className="text-2xl font-semibold mt-12 mb-6 text-[var(--text)]"
>
3. Telemetry & Diagnostics
</h2>
<p className="text-[var(--muted)]">
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&apos;t personally test on.
</p>
<p className="text-[var(--muted)] mt-4">
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).
</p>

<h2 className="text-2xl font-semibold mt-12 mb-6 text-[var(--text)]">
Expand Down Expand Up @@ -172,9 +198,9 @@ export default function PrivacyPage() {
</h2>
<p className="text-[var(--muted)]">
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.
</p>

<h2 className="text-2xl font-semibold mt-12 mb-6 text-[var(--text)]">
Expand Down
36 changes: 36 additions & 0 deletions src/components/DatadogInit.tsx
Original file line number Diff line number Diff line change
@@ -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;
}
Loading