EngineeringCodeCross Team
Harden a Framer MVP before paid traffic (2026)
A 2026 wrap-in-place playbook for founders still on Framer Sites hosting: rank the blast (custom-code secrets vs site settings, CMS write, form spam and Framer-Signature, preview vs custom domain, Publish off switch), prove the doors before ads, then decide stay-harden vs leave.
Engineering
18 min
- Secrets
- Sealed
- Forms + CMS
- Locked
- Ads
- After
Not custom code
Strangers fail closed
Proof first
Citation-ready definition: Framer Sites can look launch-ready and still leak under ads. Custom code in Project Settings ships as public HTML. A webhook secret must be 32 or more characters, stored off the client, and checked via `Framer-Signature`. CMS write belongs to Content permission, not a hidden link. Forms need Antispam set to Block. The off switch is a prior published version under Staging & Versions — not File Version History. A custom domain does not retire the `.framer.app` preview.
This note is from CodeCross (Austin registration, Pakistan engineering on a US Central overlap). Cousin tools sit on vibe coding. Buying help is the Austin app development company page. If nobody can name a prior published version tonight, use book a conversation.
Money leaves when the campaign still lists a `.framer.app` preview, a branch preview, or a form webhook that never checks a signature. A stranger can write a CMS item because Content permission sat on a shared seat. A Stripe or CRM key lived in Custom Code. Publish is green, and the only undo is “we will tweak the canvas again.” A calm canvas is not a stranger test on the name you would put on a billboard.
This essay is the pre-ads wrap while the site still lives on Framer Sites hosting. It expands Harden a Framer MVP before strangers hit Publish. It is not the first useful ship on Framer to production, not the host exit on get off Framer, not the extract on migrate from Framer, not the overlap week on transition from Framer. Softgen, Lovable, Replit, v0, and Bolt have cousin wraps — harden a Softgen MVP before paid traffic, harden a Lovable MVP before paid traffic, harden a Replit MVP before paid traffic, harden a v0 MVP before paid traffic, Bolt MVP hardening without a rewrite — and those pages are not this Sites-hosting week. The question here is narrower: can you buy a click while Framer Publish is still the process? Soft CTA: when custom-code secrets, form spam, or the Publish off switch is still red, book.
The punchy lists live on the landers. Framer MVP hardening is the clipboard for this week. Framer to production is hosting-is-not-a-ship-path. Get off Framer is the host exit. Migrate from Framer is extract. Transition from Framer is the overlap week. The vibe coding hub maps cousins. This essay is the pre-ads proof on a live Framer Sites project.
Stay on Framer hosting. Close the doors first.
The canvas is paid to look finished tonight. Paid traffic is paid to send strangers at the published URL. Those jobs collide. A green Publish badge can still leave a live key in Custom Code, a form that only looks blocked, or a preview host as the public origin.
Framer’s own docs draw the line. Guide to Framer’s hosting infrastructure (updated September 2026) is plain: every Publish is an atomic, versioned release. You can roll back to a prior version. Preview links on `.framer.app` let you test without touching the live domain. Password protection is supported. That is closer to production than a local preview. It is still a lab until ads, mail, and forms print the name you mean to keep.
How to connect a custom domain adds the quiet part. After Publish you get a Framer URL from the Publish sheet. You can add a free `framer.website` name or a domain you own. The lab names still exist. You do not need a new host this week. You do need to name who can Publish, who holds Deploy permission, and which URL ads will hit.
Rank the blast. Ads make a small leak big.
Start with the blast, not a prettier breakpoint. A stranger who dumps a Custom Code key, posts form spam into your CRM, or writes a CMS item will cost more than a restyle. Rank those doors. Close the worst one tonight.
Blast rank — close the Framer top layer first
Off switch and restore
A prior published version under Staging & Versions — not “we will tweak the canvas.” File snapshots are not a live rollback.
JSON-LD and unsafeRaw
A CMS text field dumped into the head with | unsafeRaw. One bad paste breaks the page or injects script.
Preview vs custom domain
Ads, mail, sitemap, and form success URLs that still print .framer.app, a branch preview, or a leftover framer.website name.
CMS write
Content permission on a shared seat. On-page Edit on a staging link. A form that creates collection items for strangers.
Forms and webhooks
Antispam left on Pass. No Framer-Signature check. Endpoints that accept anyone’s POST.
Custom code and site settings
Keys pasted into Project Settings → Custom Code. Webhook secrets in client scripts. Tokens a View Source can read.
Put six names on paper: who owns Custom Code, who proves forms on the advertised host, who holds Content vs Deploy, who watches form floods, who owns the public origin, and who can roll back a published version tonight. Two red names plus a campaign date means spend stays off. Soft CTA: if you cannot name a human for each layer, book.
Secrets: custom code is not a vault
Keys are the first thing ads will leak. How to add custom code (updated September 2026) is the drawer. Project Settings → Custom Code holds third-party scripts, CSS, JavaScript, and JSON-LD. You pick head or body. You pick once or on every visit. You can scope a snippet to selected pages, including CMS pages. None of that is a secret store. The published site ships that markup to every browser.
Treat every Custom Code snippet as public. A Stripe secret, a CRM API key, or a webhook signing secret in that panel is a leak. Rotate it at the issuer. Store the new value on the server that receives the form — not in a script a stranger can download. Site Settings that hold form destinations are a second drawer. A Viewer of the public site should not open them. Members, roles, and permissions split Viewer (read-only, free) from Editor, Content Editor, and Owner. Viewers of the live URL are not project members. Keep it that way.
If you pasted a live key into Custom Code, assume it leaked. If a contractor with Editor access could copy it, assume it leaked. Rotate. Then search the published HTML for the old value. Soft CTA: if the only place the key still lives is a snippet you are afraid to delete, book.
Forms: spam gates and webhook signatures
A hidden form button is not a gate. Adding a contact form says native forms can send to email, Google Sheets, or a webhook, and that spam protection and rate limiting are built in. Built-in is the start. It is not the wrap. Enable spam protection is the setting you must prove. Select the Form layer. Open Antispam. Pick Basic or Advanced. Pick Pass or Block. Then Publish. Settings apply only to new submissions after that Publish.
Basic is on by default. Advanced adds an extra check and needs Pro or higher. Pass still delivers the row and marks it. Email gets a `[Spam]` subject. Sheets get a `Framer Spam Detected` column. Webhooks get `X-Framer-Spam-Protection` and `X-Framer-Spam-Classification`. Block stops delivery. For a form that takes personal data or hits a paid API, Block is the honest default. Pass is a review queue. It is not a lock.
Connect Framer forms to a webhook is the server half. Framer POSTs JSON to an `https://` URL. Your endpoint must return 2xx. Anything else retries up to five times. Redirects (3xx) are not followed. To prove the POST came from Framer, set a secret of at least 32 characters on the webhook destination. Store it off the client. Each request sends `Framer-Signature` (SHA-256 of the body plus submission id, prefixed `sha256=`) and `Framer-Webhook-Submission-Id`. Verify both on the server. A secret in Custom Code is not verification.
Run these four checks on the advertised host. The canvas does not count:
- Antispam is Block on every mutating form. Pass-plus-a-label is not enough for email capture that hits a paid list.
- The webhook returns 2xx only after the signature matches. A 200 on every POST invites retries and junk.
- The secret is 32 or more characters and never appears in View Source.
- A stranger submit from a private window still hits the same gates. A canvas test is not that proof.
CMS write must fail closed for strangers
CMS write is the wrap ads will test if you collect stories, jobs, or leads into a collection. On-page editing is blunt. Owners and people with Content permission can edit the live site. On a custom domain, only those people see Edit. On a staging link, everyone can see the button — only permitted users can save. Visitors without project access cannot change the site. That last sentence is the bar. If a stranger can create a CMS item, you are past a hidden nav link.
On-page edits do not go live until someone with publishing permission Publishes. That is a review step. It is not a stranger lock. Members, roles, and permissions add the seat split. Content Editors manage CMS, localization, and on-page editing. Deploy publishes. When staging is on, any project member can publish to staging, and only Deploy can promote to the live domain. Name those seats. A shared Editor login is a write path.
If a form writes a CMS item, treat that form as a mutating API. Spam gates, signature checks, and a human review before Publish all apply. A collection that strangers can fill is not a brochure. If you cannot explain who can write an item after the wrap, stop calling it hardening. Open migrate from Framer when that is the honest page.
JSON-LD: prefer `| json`. Fear `unsafeRaw`.
Structured data through JSON-LD (updated September 2026) is the SEO drawer that can break the site. Custom Code can emit JSON-LD in the head. On CMS pages you bind fields with `{{Title}}`. The safe filter is `{{Title | json}}`. It escapes the value for JSON. Image fields emit a URL. Built-in `Created` and `Updated` exist on every item.
You can also store a full JSON-LD blob in a plain text CMS field and dump it with `{{variable_name | unsafeRaw}}`. Framer’s own warning is the one to keep: `unsafeRaw` does not escape. Bad HTML or bad JSON can break the page or open a script hole. A contractor paste, a CMS import, or an on-page edit can turn that field into a live injection. Stay-harden means you can name every `unsafeRaw` use — or you delete them and bind fields with `| json` instead. Do not buy ads on a head tag you cannot read.
Preview hosts and leftover Framer names leak into public links
Framer gives you several addresses that look live. They are not the same job.
Three live URLs — only one is the ad target
01 · .framer.app / staging
Lab
Base domain. Staging points it at the latest Publish while the custom name stays pinned.
02 · Branch preview
Review
Publish a branch for a share URL. It does not change main or the live site.
03 · Custom domain
Ads
The name you mean to keep. This is the only public origin.
Staging and versions is the split. Publish creates a version. Staging is available only after a custom domain is connected. With staging on, the base `.framer.app` domain tracks the latest Publish. You Deploy a chosen version to the custom domain. Roll back by Deploying an older version. How to use branches adds another URL: publish a branch to share a preview. That publish does not update main. Applying a branch updates main and still does not go live until you Publish main.
How to connect a custom domain leaves the lab names in place. A free `framer.website` (or `.photos` / `.media` / `.wiki`) name is still a Framer host. A domain you own still sits on Framer Sites. Stay-harden is fine if ads, mail, sitemap, and form links print the name you mean to keep. It is not fine if the campaign still lists a `.framer.app` preview, a branch URL, or a leftover Framer subdomain. Search the tree for those hosts. Check form redirects, canonical tags, and “view site” links in mail.
Off switch: a prior version is not “tweak the canvas”
A bad Publish needs an off switch you can name tonight. Guide to Framer’s hosting infrastructure says releases are immutable and versioned, and you can roll back, with retention based on your plan. Cache clears on updates and deletions. Staging and versions is that switch: open the version, Deploy an older one to the custom domain. Ads will not wait on a restyle.
How can I revert to a previous working version of my file is a different drawer. File → Version History (⇧⌘H / ⇧Ctrl H) shows canvas snapshots. You copy elements into the current file. Older snapshots are view-only. That path waits on a paste and another Publish. It is repair. It is not an off switch. “We will tweak the canvas again” is the sentence that fails this page.
Need the live URL dark without a redesign? Google is not indexing my site confirms built-in password protection returns 401 and keeps pages out of the index. Hosting infrastructure says password protection is supported on `.framer.app` previews. Use it as a kill switch you can flip. Delete a project also unpublishes — after Archive, and it cannot be undone. That is nuclear. Name the Deploy owner. Prove you can restore a prior published version. A feature flag on a form is extra. It does not replace a version you can Deploy in seconds.
Watching: floods, writes, and 5xx after Publish
Watching without an off switch is half a lock. Before ads, name the three signals you will actually see: form volume (and spam headers if you left Pass on a review form), CMS item creates, and errors right after Publish. Framer’s hosting guide lists DDoS protection, a firewall, and built-in form anti-spam. Those are vendor floors. They do not email you when a campaign starts filling Sheets. Point the webhook at a store you can query. Keep a human on the first 24 hours of spend. If you cannot say who would notice a flood at 11 p.m., spend stays off.
Wrap score — mark costume vs proof
Secrets
Costume
Key in Custom Code
Wrap
Moved off client
Proof
View Source is clean
Forms
Costume
Hidden button
Wrap
Antispam listed
Proof
Block + signature checked
CMS write
Costume
Shared Editor seat
Wrap
Content named
Proof
Stranger cannot create items
Public name
Costume
Ads list .framer.app
Wrap
Custom name, old links live
Proof
Sitemap + forms match
unsafeRaw
Costume
CMS blob in head
Wrap
Uses named
Proof
| json only, or none
Off / watch
Costume
“We will tweak canvas”
Wrap
Version known, no drill
Proof
Prior version Deployed once
Score each row against the advertised host, not the canvas. One red cell — a Custom Code key, Pass on a paid form, a stranger CMS write, a `.framer.app` in ads, an `unsafeRaw` you cannot name, or a rollback you have never hit — is enough to hold the spend. Move that cell. Do not greenwash the matrix.
The pre-ads week
Treat the next seven days as operator time on the Sites project, not a slogan. Inventory who can Publish, who holds Content and Deploy, and which URL ads will hit. Then seal. Then prove. Leave the host-exit pages closed until that list is honest.
Harden on Framer — seven operator steps
01 →
Inventory the public path
Who can Publish. Who has Deploy. Which URL ads will hit. Where Custom Code and form secrets live.
02 →
Seal custom code and settings
Live keys only on the server that verifies them. Rotate anything that appeared in Custom Code.
03 →
Lock forms
Antispam Block on mutating forms. Webhook secret ≥32 chars. Framer-Signature checked. 2xx only on success.
04 →
Lock CMS write
Content seats named. Stranger cannot create items. On-page Edit is not a public form.
05 →
Fix the URL map
Redirects, canonical tags, sitemap origin, form success links. No .framer.app or branch preview in ads.
06 →
Kill unsafeRaw or name it
Prefer {{field | json}}. Treat every unsafeRaw as a review item.
07
Rollback + watch, then buy
Prior published version Deployed once. Who watches form floods. Then spend.
Day 0 is inventory. Write five facts. The public URL. The project that can Publish. The person with Deploy. Whether Custom Code holds a live key. Whether a stranger can submit a mutating form. If the public origin is already taking leads and you cannot name those five, stop. You do not need a new frame. You need this list.
Seal secrets first. Then forms. Then CMS. Rate-limit and Block on the same day you move keys out of Custom Code — bots do not wait for DNS. If a webhook exists, check `Framer-Signature` against the stored secret, not a canvas guess. Then strip preview hosts. Then Deploy a prior version once so you know the off switch works. Then spend. The Framer MVP hardening clipboard is the short list. This page is the week you run it.
Illustrative operator days before a Framer ad buy
daysUnpriced Ads on a red list
3–5 wks
Campaign live. Doors still open. Cleanup later.
Illustrative operator days — not measured traffic, not a Source: Admin analytics series. Unpriced feature sprints on a public Framer site often cost more than the wrap when the first leak hits.
Treat those bars as calendar you reserve, not a vendor promise. If you cannot name the advertised host, who can Publish, and who can Deploy a prior version, the later days will thrash. The long bar is the expensive miss: a “small” test while Custom Code or a preview host is still the company. Ranges are studio-observed operator days — not a bid and not a Framer SLA.
Stay-harden vs leave. Do not mix the seats.
Pick one seat for this week. Stay-harden keeps Framer Sites as the host, with secrets out of Custom Code, forms sealed, CMS write closed, and a published-version rollback already proved. Leave opens get-off Framer and stops buying clicks that need that Publish tab. Running both seats at once is how teams rebuild pages they already had.
Stay-harden vs exit — pick one seat
Stay-harden (this page)
Process still in Framer
Sites hosting plus Publish. You accept the bill and the vendor.
Doors closed on that path
Secrets, forms, CMS write, URL map, unsafeRaw, rollback.
Ads wait for green
A red layer pauses spend, not the product.
If the public origin must leave Framer hosting, stop this wrap and open the exit. If ads are close and the origin can stay, finish the wrap first. ↓If the public origin must leave Framer hosting, stop this wrap and open the exit. If ads are close and the origin can stay, finish the wrap first.
Leave (other pages)
Process leaves Sites hosting
Export or rebuild you run. See get-off and migrate.
A custom domain is not the exit
DNS on Framer is still Framer. Rows and secrets stay until you move them.
Kill the Framer Publish tab
Site still answers when the editor is closed.
If you only need a leave date, use when to leave an AI builder. A door that will not close on this Sites project belongs on rewrite vs harden. A personal Git remote belongs on GitHub handoff. A Publish-only ship path belongs on CI/CD after an AI builder. Softgen, Lovable, Replit, and v0 have their own wrap essays — harden a Softgen MVP before paid traffic, harden a Lovable MVP before paid traffic, harden a Replit MVP before paid traffic, harden a v0 MVP before paid traffic. The Bolt cousin is Bolt MVP hardening without a rewrite. Those cousins are not this Sites-hosting week.
Wrap loop — prove, then decide
01
Prove the door
One layer. One test on the advertised URL.
02
Close it
Rotate, Block, verify, redirect, or Deploy a prior version.
03
Re-check ads list
If a layer is still red, spend stays off.
04 · loops
Stay or leave
Green wrap can stay. Red host row opens the exit.
When the list turns red
Leave the product up. Kill the campaign if any of these are still true:
- A live key still exists only in Custom Code, a site-settings paste, or a client script.
- A mutating form is still on Pass, or the webhook returns 2xx without checking `Framer-Signature`.
- A stranger can create a CMS item, or Content permission sits on a shared seat you cannot name.
- Ads, mail, or the sitemap still list a `.framer.app` preview, a branch URL, or a leftover Framer subdomain.
- An `unsafeRaw` CMS field still dumps into the head and nobody has read the live markup.
- The off switch is “we will tweak the canvas,” or you have never Deployed a prior published version.
- Two people disagree about who can Publish or who holds Deploy.
A single red door is a miss, even if Publish is green. Stop adding frames until Custom Code, forms, CMS write, and the version rollback are honest. Finish that wrap. Then spend — or open get-off Framer if Sites hosting is still the company.
Bring a second pair of hands when the founder cannot rotate a key without pasting it back into Custom Code, when form spam still lands in the CRM and the campaign is close, or when nobody has Deployed a prior version before the date. Hire for secrets, form signatures, CMS seats, and the URL map — not for a prettier canvas. Austin app development company is the studio brief. Austin mobile app development if the next door is a store binary that still points at this Framer URL.
Next steps
Walk the gates in order. Inventory the public URL, the project that can Publish, and who holds Deploy. Drain Custom Code and site-settings secrets. Set Antispam to Block on mutating forms. Verify `Framer-Signature` and return 2xx only on success. Prove a stranger cannot write CMS items. Strip `.framer.app`, branch previews, and leftover Framer subdomains from ads, mail, sitemap, and form links. Replace `unsafeRaw` with `| json` or delete the snippet. Deploy a prior published version once. Name who watches floods. Then buy the click — or open the exit if the process itself must leave Sites hosting. Pause any canvas pass that only ships from Publish while a gate is red.
CodeCross LLC is an Austin-registered product studio (1606 Headway Cir STE 9212, Austin, TX). The Framer week we run is Custom Code keys, form spam and webhook signatures, CMS write locks, preview-URL cleanup, then a published-version rollback. The Austin app development company page is the studio brief. Austin mobile app development is the store-binary engagement if the next door is a signed build that still points at this Framer URL. Company-level evidence lives on proof. When the off switch, form gates, or the advertised host is still red and the campaign is close, book a conversation.
Framer Sites is allowed to stay the host. Ads are not allowed to treat a canvas pass, a custom domain, or a Publish badge as that proof. Show a prior version you can Deploy, a form that fails closed for junk, and keys that never lived in Custom Code. Most teams never need a second codebase once those three exist.
FAQ
When Publish succeeds, did staging and the custom domain receive the same version?
Not once staging is on. Staging and versions says staging needs a custom domain. The base `.framer.app` domain then tracks the latest Publish. You Deploy a chosen version to the custom name. A canvas pass that only updated the base domain is a lab. Prove the money path on the advertised host. How to use branches is sharper: a branch preview does not change main, and applying a branch still needs Publish on main before the live site moves.
Does connecting a custom domain finish the wrap?
No. How to connect a custom domain still sits on Framer Sites. The Publish sheet URL, the `.framer.app` base, and any `framer.website` name still exist. Stay-harden is fine if ads, mail, sitemap, and form links print the name you mean to keep. It is not fine if the campaign still lists a preview host. Leaving Sites hosting is the get-off job, not this page.
If the canvas form works, does that submission exist on the advertised host?
Not as proof. Enable spam protection applies only after you Publish. Webhook setup needs a 2xx, a 32-character secret, and a server check of `Framer-Signature`. A canvas submit can look fine while the live form is still on Pass or the endpoint accepts any POST. Prove Block, signature, and a private-window submit on the advertised URL.
Can I paste keys into Custom Code and buy ads?
No. How to add custom code puts scripts in the published HTML. A webhook secret belongs on the destination, not in a browser snippet. Rotate anything that appeared in Custom Code or site settings. If a Viewer of the app can open Project Settings, sharing is still red. Do not buy ads on a red drawer.
Can strangers write CMS items if I hid the collection on the canvas?
Hiding a link is not a lock. On-page editing lets Content permission create CMS pages from the live site. Staging links show Edit to everyone; only permitted users can save. Visitors without project access should not write. If a form creates collection items, that form is a write API — spam gates and review before Publish still apply. Members, roles, and permissions is the seat list. A shared Editor login is a miss.
Is File → Version History an off switch?
No. File Version History copies canvas snapshots into the current file. You still have to Publish. The live off switch is Staging and versions: Deploy a prior published version to the custom domain. Hosting infrastructure calls those releases immutable and reversible. Password protection (401) can take the URL dark. Deleting an archived project also unpublishes — and cannot be undone. Name the Deploy owner. Hit the version rollback once before ads.
Why is `unsafeRaw` a paid-traffic risk?
Structured data through JSON-LD lets you dump a CMS text field into the head with `{{variable_name | unsafeRaw}}`. Framer warns that the filter does not escape. Invalid HTML or JSON can break the site or introduce a script risk. Prefer `{{Title | json}}` and the other `| json` bindings. If you keep `unsafeRaw`, treat every CMS edit of that field as a security review. Ads will not wait for a broken head tag.
Directional range in a few questions — not a binding quote.
Ready to price an Austin build?
Bring the problem, the users, and a budget ceiling. We’ll tell you whether an app is the right next spend — and what the first year actually costs.
Prefer writing? Send project details on the contact page.