Originkit.dev — full scrape & security report
A complete offline mirror of Originkit — a free animated-component library for Framer, React and AI tools — with an analysis of how the site is built, exactly what the scrape captured, what still works offline versus what breaks, and where the security posture is strong or weak.
01 Executive summary
Originkit is a polished, JavaScript-heavy Next.js App Router application hosted on Vercel, backed by Supabase (Postgres + auto-generated REST API) and a Cloudflare CDN for the preview videos. The whole site is a single-page-app-style component catalogue: 60 animated UI components organised into 6 categories, each with a live preview, an API reference, and a "copy the code" workflow that also plugs into Framer and into AI editors via a hosted MCP server.
Headline findings
- The scrape is complete and faithful. All 63 sitemap URLs, every referenced static asset, and all 181 preview media files were downloaded. The homepage mirror runs fully offline with videos playing from local files.
- The "premium" content is not actually protected. Every component's full source code (React and Next.js variants) is present both in each page's payload and directly readable from Supabase's public REST API without signing in — so the "Sign in to copy" and API-key gating are convenience/tracking gates, not security boundaries. This is consistent with the site's own "free library" positioning.
- Security headers are minimal. Only Strict-Transport-Security is set. There is no Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy or Permissions-Policy — leaving the site open to clickjacking and MIME-sniffing classes of issue.
- Database access control is otherwise sound. Row-Level Security correctly blocks anonymous reads of user/PII tables (user_events, invites, api_keys all return zero rows). Minor leaks: creator user-UUIDs and internal table names are disclosed.
- Interactive previews don't survive an offline scrape. Component detail pages depend on React Server Component streaming from the origin; served as static files they render the header and navigation but show loading skeletons for the live preview and API tables. The underlying data is still recoverable from the saved payloads.
02 What Originkit is
In its own words (from the /intro page): "Originkit is an animated component library built for Framer, React, and AI tools through MCP, helping designers and developers build modern websites faster." It markets itself as "the largest free animated component library." The product is currently labelled BETA.
The value proposition is simple: instead of hand-building animations, you pick a ready-made animated component, preview it, tweak its properties (colours, text, speed, size), then copy production-ready code straight into Framer, React/Next.js/Vite, or an AI coding agent.
Three ways to consume a component
- Copy Code — copy the complete .tsx source and paste it into your project.
- Copy to Framer — every component is authored "Framer-first" (default export, property controls, framer-motion animation, @framerSupportedLayout* annotations) so it drops onto a Framer canvas as a code component.
- MCP — a hosted endpoint (https://mcp.originkit.dev/mcp) exposes two tools, list_components and get_component, so an AI agent can browse the registry and fetch code adapted to your stack (framer / react / nextjs / vite).
03 How the site works
Every page is server-rendered by Next.js and then hydrated in the browser. The persistent left sidebar (search, "Get started", "Explore" sort modes, category libraries with counts, and the full component list) is shared across all routes. The main area changes per route.
The user journey
| Step | What happens | Behind the scenes |
|---|---|---|
| Browse | Homepage shows a masonry grid of ~60 auto-playing preview clips. | Each tile streams a *-gallery-720.mp4 + poster from cdn.originkit.dev (Cloudflare). |
| Open | Clicking a component opens its detail page: live preview, description, key features, API reference. | A page-view beacon fires; live view/copy counts are read from Supabase (component_stats). |
| Customise | Sliders and colour pickers adjust the component's props in real time. | Props map to a tweak_schema stored per component in the registry. |
| Copy | "Get this component" / "Copy" delivers the source, optionally adapted to your stack. | Source comes from the registry; the UI nudges you to sign in / use an API key. |
04 Architecture & technology stack
| Layer | Technology | Evidence |
|---|---|---|
| Framework | Next.js (App Router, React Server Components) | X-Powered-By: Next.js; /_next/* chunks; self.__next_f flight data |
| Hosting / edge | Vercel | Server: Vercel; X-Vercel-Cache: HIT; X-Vercel-Id |
| Media CDN | Cloudflare (cdn.originkit.dev) | Server: cloudflare; CF-RAY; immutable cache |
| Database + API | Supabase (Postgres + PostgREST) | hybpyucdpsudibzbcshj.supabase.co/rest/v1 |
| Animation | framer-motion | Present in every component's source |
| AI integration | Hosted MCP server | mcp.originkit.dev/mcp (list_components, get_component) |
| Analytics | Vercel Web Analytics + Cloudflare Web Analytics | /{id}/script.js, cdn-cgi/rum, beacon.min.js |
| Auth | Supabase Auth (client-gated /admin, /editor) | Sign-in button; protected routes redirect home |
Request flow when you load a page
# 1. HTML shell + RSC payload GET www.originkit.dev/components/<slug> → Vercel (Next.js SSR) GET /_next/static/chunks/*.js , *.css → JS/CSS bundles # 2. Preview media GET cdn.originkit.dev/components/<slug>-gallery-720.mp4 → Cloudflare GET cdn.originkit.dev/components/<slug>-variant.mp4 → Cloudflare # 3. Live data + tracking GET supabase.co/rest/v1/component_stats?slug=eq.<slug> → views / copies POST supabase.co/rest/v1/rpc/record_site_visit → visit counter POST www.originkit.dev/<analytics-id>/view → Vercel Web Analytics POST cloudflareinsights.com/cdn-cgi/rum → Cloudflare RUM
Anonymous browsing sets no cookies on the homepage — analytics is beacon-based, which is privacy-friendly for logged-out visitors.
05 Content inventory
The public sitemap lists 63 URLs: the homepage, two documentation pages (/intro, /integrations), and 60 component pages. The Supabase registry confirms exactly 60 published components across 6 categories.
| Category | Count |
|---|---|
| Text | 16 |
| Image Gallery | 14 |
| Interactive Elements | 14 |
| Animations | 9 |
| Background Animation | 5 |
| Button | 2 |
| Total | 60 |
Public routes
- / — component grid (sortable: trending / featured / new)
- /intro — what Originkit is
- /integrations — MCP / Framer / Code setup docs
- /components/<slug> — 60 detail pages
Gated routes not scraped
Advertised in robots.txt as disallowed: /admin, /editor (both redirect anonymous users home), /invite, /preview, /api (all 404 to anonymous GET).
Featured components include Glitter Wrap, Pixel Card, Spiral Images, Particle Sphere, SVG Particle, Fluid Trail, Black Hole, Juice Effect, Text Morph, Inkbleed, Mesh Text Hover and Smoky Text.
06 The scrape — what was captured
Because no Firecrawl API key was configured, the site was mirrored with curl (driven off the sitemap) plus a headless Chromium pass (Playwright) to discover the real runtime asset graph. Two copies were produced.
| Bucket | Count | Notes |
|---|---|---|
| HTML pages | 63 | All sitemap URLs, HTTP 200, saved as <path>/index.html |
| JS / CSS / fonts | 39 | 32 JS chunks, 1 CSS, 2 woff2 fonts, + 4 dynamic chunks recovered from the browser |
| CDN media | 181 | 60 grid videos, 60 variant videos, 61 posters (mp4 / jpg / png) |
| Site metadata | 8 | robots.txt, sitemap.xml, favicon, icons, logos |
| Component source | 59 / 60 | Full .tsx embedded in page payloads (only imagefold lacks it) |
Directory layout
06. Originkit.dev/ ├── mirror/ # offline-ready copy (CDN links rewritten to /cdn/) ~96 MB │ ├── index.html │ ├── intro/ , integrations/ │ ├── components/<60 slugs>/index.html │ ├── _next/static/… # JS, CSS, fonts │ ├── cdn/components/… # 181 videos + posters (local) │ ├── robots.txt, sitemap.xml, favicon.ico, icons… ├── mirror_raw/ # pristine untouched scrape (original absolute URLs) └── reports/ ├── originkit-report.html # this document └── screenshots/
Run the offline mirror
# from the project folder cd mirror python -m http.server 8099 # then open http://127.0.0.1:8099/
Serve it through a local web server (not file://) so the absolute /_next/ and /cdn/ paths resolve.
07 What works vs. what breaks after scraping
This is the crux of scraping a modern Next.js app: the server-rendered HTML and all media are captured, but anything that depends on React Server Component streaming or live backend calls cannot fully reproduce offline. Verified by serving the mirror locally and inspecting it in a real browser.
Works offline
- Homepage: full layout, sidebar, category counts
- Preview grid videos & posters (served locally)
- All page text, headings, SEO metadata
- /intro and /integrations content
- Fonts, CSS, favicons, icons
- Hard navigation between the 63 saved URLs
Breaks / degraded offline
- Live animated component previews (need dynamic chunks + RSC)
- Component detail body → loading skeletons (RSC stream never resolves)
- Live view/copy counts (Supabase calls fail)
- Search, sign-in, "Copy", MCP fetch
- Analytics beacons (Vercel + Cloudflare, blocked by CORS)
- Soft client-side navigation (RSC prefetch returns HTML)
Important nuance — the content is still there
The component descriptions, key-feature lists, API reference tables and full source code are all embedded in the saved HTML inside the self.__next_f flight payloads — they simply aren't painted on screen offline. They are fully recoverable by parsing the saved files, so no information was lost in the scrape; only the live rendering degrades.
08 Security assessment
Scope: passive, read-only assessment of publicly exposed surfaces only — the same endpoints the site itself calls from every visitor's browser. No writes, no authentication bypass, no data exfiltration were attempted.
Findings at a glance
| # | Finding | Severity | Status |
|---|---|---|---|
| S1 | Missing security response headers (CSP, X-Frame-Options, etc.) | Medium | Open |
| S2 | Gated "premium" source freely readable via anon Supabase API | Low / By design | Note |
| S3 | Database schema / table names leaked via PostgREST 404 hints | Low | Open |
| S4 | Creator user-UUIDs exposed via components.created_by | Low | Open |
| S5 | Admin/editor gating is client-side redirect only | Low | Note |
| S6 | RLS correctly protects user/PII tables | Good | Pass |
S1 · Missing security headers — Medium
Only one security header is returned by the application origin:
| Header | Present? | Impact if absent |
|---|---|---|
| Strict-Transport-Security | Yes (max-age 2y) | — |
| Content-Security-Policy | No | No defence-in-depth against XSS / injection |
| X-Frame-Options | No | Page can be framed → clickjacking |
| X-Content-Type-Options | No | MIME-sniffing of responses |
| Referrer-Policy | No | Full referrer leaked cross-origin |
| Permissions-Policy | No | No restriction on camera/mic/geo APIs |
Recommendation: add a baseline header set (easy on Vercel via next.config.js headers or vercel.json): X-Frame-Options: DENY (or CSP frame-ancestors 'none'), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, a starter Content-Security-Policy, and includeSubDomains; preload on HSTS.
S2 · "Gated" component source is public — Low / by design
The UI encourages signing in or using an API key to copy code, but the full source is trivially available two ways: (1) embedded in each page's payload, and (2) directly from the registry table over the anonymous REST API:
# anonymous read — returns all 60 published components incl. full source GET https://…supabase.co/rest/v1/components?select=source,nextjs_source apikey: sb_publishable_UlU4… # embedded in the site's JS → 200 OK — source (21 KB) + nextjs_source (18 KB) per component
Because Originkit brands itself as a free library, this is most likely intentional. The takeaway is simply that the sign-in / API-key flow provides tracking and convenience, not access control over the code. If any component is ever meant to be paid or unreleased, it must not live in an anon-readable row. (At scan time all 60 rows were status: published; no drafts leaked.)
S3 · Schema disclosure via PostgREST hints — Low
Requesting a non-existent table returns a helpful hint that names real tables, disclosing internal schema:
GET /rest/v1/users → 404
{ "code":"PGRST205", "hint":"Perhaps you meant the table 'public.user_events'" }
# similarly reveals: invites, invite_redemptions, …
Recommendation: this is default PostgREST behaviour; if undesirable, restrict the exposed schema or disable hint verbosity at the API gateway.
S4 · Creator UUID exposure — Low
The public components rows include created_by, exposing 3 distinct internal user UUIDs. Low impact on its own, but it links content to specific accounts and widens the attack surface if combined with other leaks. Consider dropping created_by from the anon-facing column set (a Postgres view or column-level policy).
S5 · Client-side-only route gating — Low / note
/admin and /editor both return HTTP 200 and then redirect anonymous users to the homepage in the browser. That is a UX gate, not a security boundary — the real protection must be (and, based on the RLS results, appears to be) enforced server-side via Supabase policies. Worth confirming that every privileged mutation is RLS-guarded and not merely hidden behind the redirect. Note also that robots.txt advertises these paths to anyone reading it.
S6 · Row-Level Security is working — Good
The sensitive tables are properly locked down. With the public key, anonymous reads return zero rows, not data:
| Table | Anon read | Verdict |
|---|---|---|
| user_events | 200 → 0 rows | Protected |
| invites | 200 → 0 rows | Protected |
| invite_redemptions | 200 → 0 rows | Protected |
| api_keys | 200 → 0 rows | Protected |
| components | 200 → 60 rows | Public (intended) |
| component_stats | 200 → public | Public (intended) |
Not tested (responsibly out of scope)
Write access (INSERT/UPDATE/DELETE) through the anon key was not attempted, since that could modify live data. RLS write-policies should be independently reviewed to confirm the anon role cannot mutate components, component_stats, or trigger the record_site_visit RPC abusively.
09 Notable observations & hygiene
- Stray CDN asset. A file literally named WhatsApp Video 2026-07-02 at 11.40.56 AM.mp4 is referenced from the CDN — an accidental upload left in the media bucket. Harmless, but worth cleaning up.
- Orphan stats rows. component_stats contains slugs (asciiwaves, curvegallery22, flicker) that have no published component — leftover analytics from removed or renamed components. Their preview media still sits on the CDN.
- One component missing embedded source. imagefold is the only detail page whose payload does not carry the .tsx source (still available via the registry API).
- Truncated poster reference. The floatingicons page contains a malformed …poster.jp reference alongside the correct .jpg; the correct file loads fine, so it is cosmetic.
- Stale counters in the registry. components.copy_count reads 0 for all rows; the real counts live in component_stats (e.g. Click Effects: 303 views / 34 copies).
- Privacy-friendly default. No cookies are set for anonymous visitors; tracking is beacon-only.
10 Appendix
Methodology
- Discovered routes from sitemap.xml (63 URLs) and robots.txt.
- Downloaded every page and referenced static asset with curl.
- Ran a headless Chromium (Playwright) pass over the live site to capture the real runtime network graph, console output, and the dynamic chunks not present in static HTML.
- Downloaded all 181 CDN preview media files and rewrote CDN links to local /cdn/ paths in the mirror/ copy.
- Verified the mirror by serving it locally and comparing offline vs. live rendering in a browser.
- Security testing was passive and read-only against publicly exposed endpoints.
Key endpoints referenced
| Purpose | Endpoint |
|---|---|
| App origin | https://www.originkit.dev |
| Media CDN | https://cdn.originkit.dev |
| Database / REST API | https://hybpyucdpsudibzbcshj.supabase.co/rest/v1 |
| MCP server | https://mcp.originkit.dev/mcp |
Prioritised recommendations
- Add security headers (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) via vercel.json / next.config.
- Trim the anon column set on components — drop created_by and keep drafts/unreleased work out of anon-readable rows.
- Review RLS write policies to confirm the anon key cannot mutate data or abuse RPCs.
- Reduce schema disclosure from PostgREST error hints if internal table names are considered sensitive.
- Housekeeping — remove the stray WhatsApp video and orphaned CDN media / stats rows.
PDF version
For sharing in messaging apps, this report can be exported to PDF: open it in a browser and use Ctrl+P → "Save as PDF". A light-on-white print stylesheet is built in. A pre-rendered originkit-report.pdf can also be generated on request.