How to fix custom code optimization errors like “Cannot Set Property of Undefined”

Optimization issues often occur when custom code components or overrides depend on browser-specific APIs. This guide explains why these errors arise and how to resolve them.

Why optimization issues occur

Framer pre-renders pages on the server to improve performance and ensure compatibility across all devices. However, during pre-rendering:

  • Browser-specific APIs like window, document, and navigator are not available because the server lacks browser context (e.g., browser settings, window size, cookies).

  • Custom code that relies on these APIs will cause errors during pre-rendering.

Avoid browser-specific APIs

Write JavaScript that doesn’t rely on browser APIs for rendering.

  • Instead of: Using window.innerWidth.

  • Use: CSS media queries to handle layout changes based on screen size.

For example:

// ❌️ Bad: will cause optimization issues
export function Component() {
  const windowWidth = window.innerWidth

  return windowWidth < 768 ? <MobileVideo /> : <DesktopVideo />
}

// ✅ Good: won’t cause optimization issues
import { withCSS } from "framer"

function Component() {
  return <>
    <style>{`
      .my-component-video-mobile { display: block }
      .my-component-video-desktop { display: none }
        
      @media (min-width: 768px) {
        .my-component-video-mobile { display: none }
        .my-component-video-desktop { display: block }
      }
    `}</style>
    <div className="my-component-video-mobile"><MobileVideo /></div>
    <div className="my-component-video-desktop"><DesktopVideo /></div>
  </>
}
// ❌️ Bad: will cause optimization issues
export function Component() {
  const windowWidth = window.innerWidth

  return windowWidth < 768 ? <MobileVideo /> : <DesktopVideo />
}

// ✅ Good: won’t cause optimization issues
import { withCSS } from "framer"

function Component() {
  return <>
    <style>{`
      .my-component-video-mobile { display: block }
      .my-component-video-desktop { display: none }
        
      @media (min-width: 768px) {
        .my-component-video-mobile { display: none }
        .my-component-video-desktop { display: block }
      }
    `}</style>
    <div className="my-component-video-mobile"><MobileVideo /></div>
    <div className="my-component-video-desktop"><DesktopVideo /></div>
  </>
}
// ❌️ Bad: will cause optimization issues
export function Component() {
  const windowWidth = window.innerWidth

  return windowWidth < 768 ? <MobileVideo /> : <DesktopVideo />
}

// ✅ Good: won’t cause optimization issues
import { withCSS } from "framer"

function Component() {
  return <>
    <style>{`
      .my-component-video-mobile { display: block }
      .my-component-video-desktop { display: none }
        
      @media (min-width: 768px) {
        .my-component-video-mobile { display: none }
        .my-component-video-desktop { display: block }
      }
    `}</style>
    <div className="my-component-video-mobile"><MobileVideo /></div>
    <div className="my-component-video-desktop"><DesktopVideo /></div>
  </>
}

Put browser-specific API calls into useEffect

If you can’t avoid using browser-specific APIs, try moving them inside useEffect instead. useEffect executes only in the browser, when the page has fully loaded, so it won’t cause optimization issues. For example:

// ❌️ Bad: will cause optimization issues
function Component() {
  window.gtag("event", "component_rendered")

  return <div>Hello!</div>
}

// ✅ Good: won’t cause optimization issues
function Component() {
  useEffect(() => {
    window.gtag("event", "component_rendered")
  }, [])

  return <div>Hello!</div>
}
// ❌️ Bad: will cause optimization issues
function Component() {
  window.gtag("event", "component_rendered")

  return <div>Hello!</div>
}

// ✅ Good: won’t cause optimization issues
function Component() {
  useEffect(() => {
    window.gtag("event", "component_rendered")
  }, [])

  return <div>Hello!</div>
}
// ❌️ Bad: will cause optimization issues
function Component() {
  window.gtag("event", "component_rendered")

  return <div>Hello!</div>
}

// ✅ Good: won’t cause optimization issues
function Component() {
  useEffect(() => {
    window.gtag("event", "component_rendered")
  }, [])

  return <div>Hello!</div>
}

Use placeholders for browser-dependent data

If your component needs information like document.cookie (e.g., user login status) or navigator.language:

  1. Write a component that shows a placeholder during pre-rendering.

  2. After the page loads, update the component with the correct data.

Example: framer-optim-1.jsx

Opt out of optimization

If necessary, you can opt your component out of optimization entirely:

  1. Skip pre-rendering for the component using server-side logic.

  2. Note:

    • The component’s content won’t be accessible to search engines.

    • It will only load after the page has fully loaded.

    • Use a placeholder to provide a fallback experience for better usability.

Example: framer-optim-2.jsx

Apply the same approach to overrides

For custom overrides:

  • Use placeholders or opt out of optimization in a similar way to components.

Example: framer-optim-3.jsx

If you're still experiencing issues, please reach out to us through our contact page for further help or check out the Developer Space.


Example: framer-optim-3.jsx

If you're still experiencing issues, please reach out to us through our contact page for further help or check out the Developer Space.

FAQ

Lesson FAQ

  • Why do optimization errors like 'Cannot set property of undefined' occur in Framer when using custom code?

    Framer pre-renders pages on the server to improve performance and ensure compatibility across all devices. During pre-rendering, browser-specific APIs like window, document, and navigator are not available because the server lacks browser context. Custom code that relies on these APIs will cause errors during pre-rendering, leading to issues such as 'Cannot set property of undefined.'

  • How can I safely use browser-specific APIs like window or document in my Framer components?

    If you can’t avoid using browser-specific APIs, move them inside useEffect instead. useEffect executes only in the browser, when the page has fully loaded, so it won’t cause optimization issues. For example: // ✅ Good: won’t cause optimization issues function Component() { useEffect(() => { window.gtag("event", "component_rendered") }, []) return <div>Hello!</div> }

  • What is the recommended way to handle responsive layouts in Framer custom code without causing optimization errors?

    Write JavaScript that doesn’t rely on browser APIs for rendering. Instead of using window.innerWidth, use CSS media queries to handle layout changes based on screen size. For example, use CSS classes and media queries to show or hide components for different screen sizes, rather than relying on JavaScript to detect window size during rendering.

Updated