Guard logic for Canvas vs Preview
Guard
When a code component runs inside Framer it can be in two places: the Canvas (editor) or Preview (runtime). Some APIs and behaviors are unsafe or slow in the Canvas. Always detect the environment and guard side effects accordingly.
Why
Canvas runs inside the editor. It can be slow, may not have
When you build code components for Framer, you're writing React but your components live in two worlds:
the Canvas (where designers drop, resize, and preview in the editor)
and the Preview (the actual runtime your end users see).
Most of the time, we don't think about the difference... until something breaks.
Maybe your fetch()
runs 50 times in the editor.
Maybe window
is undefined and your component silently fails.
Or worse: your component lags the entire Canvas because it's trying to animate or load resources in the background.
This is where one simple guard can save you hours of debugging.
The Golden Rule
Always check whether your component is running inside the Canvas or Preview before running logic that touches the browser, network, or performance-heavy code.
Framer gives us a built-in way to detect that.
This single line changes everything.
Why It Matters
The Canvas is not a browser: it's a controlled environment where Framer renders your component tree inside the editor.
Some APIs are restricted or behave differently.
Here's what typically breaks when you don't guard:
fetch()
loops indefinitely because the Canvas re-renders oftenResizeObserver
orIntersectionObserver
runs thousands of times while draggingrequestAnimationFrame
causes the editor to lagFonts, videos, or scripts try to load before the preview even starts
You trigger side effects that Framer can't clean up when switching pages
By guarding your logic, you give the editor a lightweight placeholder and reserve the heavy lifting for preview time.
The Core Pattern
Here's a basic skeleton you can copy into any Framer code component.
What's happening here
We detect the environment once at the top
Inside
useEffect
, we skip all side effects if we're on the CanvasWe render a minimal placeholder instead of the full component in edit mode
In Preview, the real logic runs: here simulated with a mock async call
This makes the component instant in the editor, but fully functional at runtime.
Common Use Cases
Use case | What to guard |
---|---|
Fetching data | Skip all API calls in Canvas. Instead, render mock data or a placeholder. |
Playing media | Avoid autoplay or preloading in Canvas. Use static preview thumbnails instead. |
Running timers or loops | Only start |
Loading fonts or scripts | Guard |
Using observers | Disconnect |
Bonus: Mock Data Mode
Sometimes you do want to show something in Canvas that feels real but without hitting your live API.
Here's how to handle that safely.
This lets you keep the Canvas visual while still protecting performance.
Real-World Example
Here's a snippet from one of our internal components: a live analytics widget that fetches daily revenue.
If you remove the guard, it will spam the API every few seconds while designing.
Best Practices Checklist
Detect environment once at the top
Skip side effects in Canvas
Show a clean placeholder in Canvas mode
Clean up observers, timers, and listeners on unmount
Avoid DOM-heavy logic in the editor
Never fetch live data or run loops inside Canvas
Make defaults beautiful so the placeholder still feels designed
Closing Thought
The difference between a "Framer beginner component" and a "production-ready component" often comes down to this guard.
Checking the environment before you run logic isn't just about avoiding bugs: it's about designing for Framer itself.
Your users shouldn't feel lag while editing. Your previews shouldn't behave differently than design mode.
So the next time you add useEffect
, fetch
, or a heavy animation:
just ask yourself:
"Should this run in the Canvas?"
If the answer is no, you already know what to do.