Framer Exporter

VerifiedCaution

Export a Framer website to fully local HTML/JS/CSS with no CDN dependencies. Use to self-host, remove Framer branding, or create an offline-capable version.

Sby Skills Guide Bot
DevelopmentAdvanced
7/23/2026
Claude Code
#framer#self-hosting#static-site-export#es-modules#asset-download

Recommended for

Automated summary

This skill downloads a Framer site (live URL or local export) into fully local HTML/JS/CSS files with no Framer CDN dependencies.

Strengths

  • Downloads and sorts JS, CSS, images and media assets into dedicated local folders
  • Rewrites static and dynamic ES module imports plus modulepreload links to point at local files
  • Handles multi-page exports by reading the data-framer-hydrate-v2 routeIds and generates a server.js for SPA routing
  • Strips the "Made in Framer" badge and editor bars, and validates media downloads via magic bytes

Limitations

  • Relies on the described Framer export structure (.mjs naming, data-framer-hydrate-v2), so heavily customized sites or custom code components may break
  • Fonts are skipped by default and must be requested explicitly
  • Requires network access to the CDN and running server.js for SPA routes to resolve locally
When to use it

Use it when you want to self-host a Framer site, remove Framer branding, or produce an offline-capable copy.

When not to use it

Avoid it if the site was not exported by Framer or if you only need a visual backup without rewriting JS modules.

Security analysis

Caution
Quality score74/100

The skill is a legitimate, well-scoped site-mirroring tool: it fetches public CDN assets, rewrites imports and HTML paths, strips branding, and writes a small local server. The risk profile is that of a powerful but normal dev workflow — network downloads, recursive file edits, a targeted directory deletion, and executing a generated server.js. There is no evidence of exfiltration, destructive absolute-path deletion, or obfuscation, so it warrants 'caution' rather than 'risky'.

Findings
  • •Uses Bash/network to download arbitrary remote assets (JS/MJS modules, media) from Framer CDNs and then executes nothing, but the downloaded JS is later served locally via a generated Node server
  • •Step 7 deletes directories (limited to 'empty' static HTML dirs, but the guard is heuristic and a mis-classified directory could remove user files)
  • •Generates and runs a local server.js — running it via `node server.js` executes agent-authored code
  • •No secret exfiltration, no curl|sh piping, no obfuscated payloads, no safety-disabling instructions
How this analysis is made

Examples

Export a live Framer site
Export https://example.framer.app to local HTML/JS/CSS files in ./site so I can self-host it without any Framer CDN calls.
Clean up a local export
Take my local Framer export in ./my-exported-site, download all CDN assets into js/, css/, images/ and media/, and remove the 'Made in Framer' badge.
Fix sub-page routing
My self-hosted Framer export breaks on /blogs and /pricing — fix the SPA routing, rewrite the modulepreload links, and generate a server.js with URL-to-HTML mapping.

name: framer-export description: Export a Framer website to fully local HTML/JS/CSS with no CDN dependencies. Use when the user wants to self-host a Framer site, remove Framer branding, or create an offline-capable version. Works on any Framer-exported site. disable-model-invocation: true allowed-tools: Bash, Read, Grep, Write, Edit, Glob, TaskCreate, TaskUpdate, TaskList, TaskGet

Framer Exporter Skill

Export any Framer website to fully self-hosted local files with no Framer CDN dependencies.

What This Does

  1. Downloads all assets — JS, CSS, images, video, PDF, audio, and other files from Framer CDN to local js/, css/, images/, media/ folders
  2. Fixes ES module imports — Updates all import and import() paths to use local filenames, including modulepreload links
  3. Handles multi-page exports — Detects and processes all HTML pages (blog posts, policy pages, sub-routes) with their unique data-framer-hydrate-v2 routeIds
  4. Removes Framer noise — Strips "Made in Framer" badges, editor bars, and Framer branding precisely
  5. Fixes SPA routing — Updates nav links, deletes conflicting directories, generates a custom server.js with URL-to-HTML mapping

Usage

Export a live Framer site

/framer-export https://example.framer.app

Export from local HTML files

/framer-export ./my-exported-site

Workflow

Step 1: Analyze the site

  • If URL: download the HTML and scan for all external CDN URLs
  • If local: scan all HTML files for CDN references
  • Categorize correctly by checking file extensions using regexes (e.g. /\.(js|mjs)(\?|$)/i for JS, /\.css(\?|$)/i for CSS, /\.(png|jpg|jpeg|webp|gif|svg|ico)(\?|$)/i for images). This ensures files with query parameters (e.g., ?v=2) are not misclassified as media files.
  • Detect all page routes: Every .html file found represents a unique route (homepage /, /blogs, /pricing, /terms-conditions, /blogs/slug-title, etc.)
  • Each HTML file contains data-framer-hydrate-v2="{routeId:...}" — this JSON determines which page renders on the client and is baked in at download time, so each route needs its own HTML file
  • Log all discovered routes

Step 2: Create local asset directories

Create js/, css/, images/, media/ directories alongside index.html.

Step 3: Download all external resources

Download all JS, CSS, images, and media files (video, PDF, audio, documents) to local directories. Skip fonts by default unless user requests them.

  • Media Validation: Validate downloaded files. For videos (MP4, WebM, Ogg) and audio, read the first 12 bytes to verify magic bytes. MP4 contains ftyp at offset 4, WebM/MKV starts with \x1a\x45\xdf\xa3. Reject empty files.

Important: Extract dynamic import URLs from script_main.mjs. Framer's SPA router dynamically imports page modules. Construct full CDN URLs from the script_main base path, and download those dynamic modules too.

Step 4: Fix ES module imports in JS files

Many Framer exports have import statements referencing CDN filenames like 7zd_4hdYd8O.mjs. Rename these to short local names and update all import paths:

  • from "./7zd_4hdYd8O-dG7PZxJrnFUX2tGHHFGd1cKXxhsQWgA.B72Ql4Dm.mjs" → from "./site-home.mjs"
  • Also fix dynamic imports: import(`./filename.mjs`)
  • Also fix modulepreload links.

Step 5: Update HTML references

Replace all CDN URLs in HTML files with absolute root-relative paths (starting with /) to ensure sub-pages and nested routes resolve correctly:

  • https://framer.com/bootstrap.js → /js/bootstrap.js
  • Images: https://framerusercontent.com/images/xxx.png → /images/xxx.png (strip query params)
  • Media (video/PDF/audio): https://framerusercontent.com/files/xxx.pdf → /media/xxx.pdf
  • Modulepreload links: Rewrite relative/CDN modulepreload href values to /js/filename.mjs but ignore any links that are already absolute (starting with /) or external (starting with http/https) to avoid double-prefixing.

Step 6: Remove Framer noise

Surgically remove Framer badge, editor bar, iframe, and related CSS/scripts. Update all HTML files, not just the homepage.

Step 7: Fix SPA routing

  1. Delete empty static HTML directories (blog/, support/, etc.) that override SPA routes — but ONLY if they contain no actual HTML files
  2. Update nav links from .html paths to SPA routes: href="blog/index.html" → href="/blog". Skip relative asset directory prefixes (js/, css/, images/, media/) and file extensions to avoid breaking asset loading.
  3. Generate a custom server.js that maps each discovered URL slug to its HTML file.
  4. The server.js template must double-escape regexes (e.g. url.replace(/^\\//, '') in template string) to strip leading slashes correctly.

Step 8: Verify

  • Run: node server.js
  • Test all routes and test page refresh on sub-pages and nested pages to check for any blank screens or 404s.
  • Check browser console for "Failed to fetch dynamically imported module" errors.

Important Framer Patterns

data-framer-hydrate-v2

Framer bakes data-framer-hydrate-v2="{routeId:...,...}" JSON into each HTML page. This routeId is set at download time — each unique URL needs its own HTML file because the routeId cannot be dynamically changed after download.

CDN import paths to fix

Framer uses hash-based filenames. Common patterns:

https://framer.com/bootstrap.[hash].js
https://app.framerstatic.com/chunk-[hash].mjs
https://framerusercontent.com/sites/[siteId]/[hash].mjs

Route modules

Framer SPAs define routes in site-script_main.mjs:

W = {
  routeId: { page: () => import('./route-page.mjs'), path: '/path' },
  ...
}

The route .mjs files often import each other — must update ALL import paths recursively.

Dynamic imports in route files

Route files often import other modules dynamically:

page: E(() => import(`./some-file.mjs`))

These also need fixing.

Image URL variants

Framer URLs appear in multiple attributes:

src="https://framerusercontent.com/images/xxx.png?width=101&height=101"
srcset="https://framerusercontent.com/images/xxx.png?w=800 800w, ..."
href="https://framerusercontent.com/images/xxx.png?..." (favicon)
content="https://framerusercontent.com/images/xxx.png?..." (og:image)

Strip query parameters from all of these and map to images/.

Framer font files

framerusercontent.com/assets/*.woff2 custom fonts — these are design fonts with no Framer branding. It's acceptable to keep them as external references. Skip by default, offer --with-fonts to download.

Output Structure

project/
├── index.html              (cleaned, local refs)
├── server.js               (custom SPA server with URL→HTML mapping)
├── js/
│   ├── bootstrap.js
│   ├── site-script_main.mjs
│   ├── site-[name].mjs
│   ├── route-[page].mjs
│   └── ...
├── css/
│   └── editorbar.css
├── images/
│   └── [all images]
└── media/
    └── [videos, PDFs, audio, documents, etc.]

Edge Cases

  • Port conflicts: Kill existing processes on the port before starting server (taskkill //F //IM node.exe on Windows)
  • Static .html files: If nav links point to .html files that exist, update those files' CDN refs too
  • Empty dirs vs real dirs: blog/ with only empty subdirs → delete; blog/ with index.html → keep and clean
  • Blog post slugs: URLs like /blogs/top-ai-tools need their own blogs/top-ai-tools.html file — extract from data-framer-hydrate-v2 or from the SPA router config
  • Font files: Skip by default; no visible branding but adds significant export time
  • Canvas sandbox iframe: Editor-only, safe to remove (already caught by noise removal)

From the file to a first result

The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.

View the source and supporting files

This download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.

1. Download the file

Download SKILL.md

From the root of a test project, save the file as .skill-downloads/framer-exporter-mrx3xwu0/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.

Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.

mkdir -p '.skill-downloads/framer-exporter-mrx3xwu0' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/framer-exporter-mrx3xwu0/download' --output '.skill-downloads/framer-exporter-mrx3xwu0/SKILL.md.part' && mv '.skill-downloads/framer-exporter-mrx3xwu0/SKILL.md.part' '.skill-downloads/framer-exporter-mrx3xwu0/SKILL.md'

2. Check prerequisites

Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.

Tools declared by the author (check availability in your agent): Bash, Read, Grep, Write, Edit, Glob, TaskCreate, TaskUpdate, TaskList, TaskGet

No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.

The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.

3. Load the skill

After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.

Claude Code
test -f '.skill-downloads/framer-exporter-mrx3xwu0/SKILL.md' && test -s '.skill-downloads/framer-exporter-mrx3xwu0/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/framer-export' && cp -R '.skill-downloads/framer-exporter-mrx3xwu0' '.claude/skills/framer-export'

OpenSkills

OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.

Official OpenSkills installation
openskills install './.skill-downloads/framer-exporter-mrx3xwu0'

openskills read 'framer-exporter-mrx3xwu0'

Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.

For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.

openskills sync

Manual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.

4. Try a first task

Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:

Read .skill-downloads/framer-exporter-mrx3xwu0/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.

Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.

Related skills