# Self is not defined error using UI toolkit in NextJS

**URL:** <https://devforum.zoom.us/t/self-is-not-defined-error-using-ui-toolkit-in-nextjs/120241>\
**Category:** Video SDK\
**Tags:** video-sdk\
**Created:** [November 3, 2024, 7:39pm UTC](https://devforum.zoom.us/t/self-is-not-defined-error-using-ui-toolkit-in-nextjs/120241 "2024-11-03T19:39:51Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![edisonfreire14](https://avatars.discourse-cdn.com/v4/letter/e/5e9695/32.png) [@edisonfreire14](https://devforum.zoom.us/u/edisonfreire14)\
**Post date:** [November 3, 2024, 7:39pm UTC](https://devforum.zoom.us/t/self-is-not-defined-error-using-ui-toolkit-in-nextjs/120241/1 "2024-11-03T19:39:51Z")

</div>

Im a using the Zoom Video SDK ui toolkit in my Next.js 14.2.4, that is using the app router and typescript.  
I tried to completely copy the code from `https://github.com/zoom/videosdk-ui-toolkit-react-sample` , it worked in development server meaning I would be able to join calls and get the proper UI but I would get errors in terminal saying, this would stop me from pushing to github as Vercel would raise errors for self is not defined as well:

```auto
 ⨯ ReferenceError: self is not defined
    at __webpack_require__ (/Users/edison/notes/nextjs-dashboard/.next/server/webpack-runtime.js:33:43)
    at __webpack_require__ (/Users/edison/notes/nextjs-dashboard/.next/server/webpack-runtime.js:33:43)
    at eval (./app/telehealth/call/page.tsx:7:83)
    at (ssr)/./app/telehealth/call/page.tsx (/Users/edison/notes/nextjs-dashboard/.next/server/app/telehealth/call/page.js:348:1)
    at Object. __webpack_require__ [as require] (/Users/edison/notes/nextjs-dashboard/.next/server/webpack-runtime.js:33:43)
    at JSON.parse (<anonymous>)
digest: "3611744330"
 GET /telehealth/call 500 in 82ms

```

here is my code:

```auto
'use client';
import uitoolkit from "@zoom/videosdk-ui-toolkit";
import "@zoom/videosdk-ui-toolkit/dist/videosdk-ui-toolkit.css";

function App() {
  let sessionContainer: HTMLDivElement | null = null;
  // set your auth endpoint here 
  // a sample is available here: https://github.com/zoom/videosdk-auth-endpoint-sample
  const authEndpoint = "/api/getToken"; // http://localhost:4000
  const config = {
    videoSDKJWT: "",
    sessionName: "test",
    userName: "React",
    sessionPasscode: "123",
    features: ["video", "audio", "settings", "users", "chat", "share"],
    options: { init: {}, audio: {}, video: {}, share: {} },
    virtualBackground: {
      allowVirtualBackground: true,
      allowVirtualBackgroundUpload: true,
      virtualBackgrounds: ['https://images.unsplash.com/photo-1715490187538-30a365fa05bd?q=80&w=1945&auto=format&fit=crop']
    }
  };
  const role = 1;

  function getVideoSDKJWT() {
    sessionContainer = document.getElementById("sessionContainer") as HTMLDivElement;
    document.getElementById("join-flow")!.style.display = "none";
    fetch(authEndpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ sessionName: config.sessionName, role: role, }),
    }).then((response) => {
      return response.json();
    }).then((data) => {
      if (data.signature) {
        console.log(data.signature);
        config.videoSDKJWT = data.signature;
        joinSession();
      } else {
        console.log(data);
      }
    }).catch((error) => {
      console.log(error);
    });
  }

  function joinSession() {
    console.log(config);
    if (sessionContainer) {
      uitoolkit.joinSession(sessionContainer, config);
      sessionContainer && uitoolkit.onSessionClosed(sessionClosed);
    }
  }

  const sessionClosed = () => {
    console.log("session closed");
    sessionContainer && uitoolkit.closeSession(sessionContainer);
    document.getElementById("join-flow")!.style.display = "block";
  };

  return (
    <div className="App">
      <main>
        <div id="join-flow">
          <h1>Zoom Video SDK Sample React</h1>
          <p>User interface offered by the Video SDK UI Toolkit</p>
          <button onClick={getVideoSDKJWT}>Join Session</button>
        </div>
        <div id="sessionContainer"></div>
      </main>
    </div>
  );
}

export default App;

```

I tried using dynamic from next/dynamic to import uitoolkit from “@zoom/videosdk-ui-toolkit” on the client side, that did remove the error from the terminal but also made all functionality stop working and I was no longer able to use that actual ui toolkit. So it was pointless.

---

<div class="post-metadata">

**Author:** ![lastreaction17](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/lastreaction17/32/57661_2.png) [@lastreaction17](https://devforum.zoom.us/u/lastreaction17)\
**Post date:** [November 4, 2024, 1:59pm UTC](https://devforum.zoom.us/t/self-is-not-defined-error-using-ui-toolkit-in-nextjs/120241/2 "2024-11-04T13:59:15Z")

</div>

The ReferenceError: self is not defined error is occurring because the Zoom Video SDK UI Toolkit is likely trying to access self, which is a browser-specific object not available in the server environment where Next.js also tries to execute the code. Next.js uses server-side rendering (SSR) by default, and libraries like the Zoom Video SDK often depend on browser-only APIs.

Here’s how you can adjust your code to make sure it only executes in the client environment:

- Use next/dynamic with ssr: false: This ensures that the code only runs on the client side, skipping SSR entirely for this component.

- Separate Toolkit Initialization Logic: Make sure to handle initialization logic only when the component is fully loaded on the client.

---

<div class="post-metadata">

**Author:** ![kellyjandrews](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/kellyjandrews/32/51599_2.png) [@kellyjandrews](https://devforum.zoom.us/u/kellyjandrews)\
**Post date:** [November 6, 2024, 11:46am UTC](https://devforum.zoom.us/t/self-is-not-defined-error-using-ui-toolkit-in-nextjs/120241/3 "2024-11-06T11:46:17Z")

</div>

This is the correct answer - even though it’s a client component it is rendered on the server, so the UI toolkit will need to be rendered _after_ the page has loaded in the DOM.

> **[Rendering: Client Components | Next.js](https://nextjs.org/docs/app/building-your-application/rendering/client-components)**
>
> Learn how to use Client Components to render parts of your application on the client.

> **[Why do Client Components get SSR'd to HTML? · reactwg/server-components ·...](https://github.com/reactwg/server-components/discussions/4)**
>
> If you're familiar with React, your mental model before RSC might look similar to this (blank space on the left is intentional): RSC does not change that mental model, but it adds a new layer befor...

---

<div class="post-metadata">

**Author:** ![ekaansh.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/ekaansh.zoom/32/55004_2.png) [@ekaansh.zoom](https://devforum.zoom.us/u/ekaansh.zoom)\
**Post date:** [November 6, 2024, 11:50am UTC](https://devforum.zoom.us/t/self-is-not-defined-error-using-ui-toolkit-in-nextjs/120241/4 "2024-11-06T11:50:42Z")

</div>

Hey @edisonfreire14, here’s how you can import the SDK:

```jsx
import dynamic from "next/dynamic";

const Videocall = dynamic<{ slug: string; JWT: string }>(
  () => import("../../../components/Videocall"),
  { ssr: false },
);

export default async function Page() {
  return (
      <Videocall slug={params.slug} JWT={jwt} />
  );
}

```

You can then use the SDK/UIToolkit in the Videocall component. You can find a real world Next.js example using the app router [here](https://github.com/zoom/videosdk-nextjs-quickstart/blob/2539cde5787c446ac6debb9d50169ec8287d79d6/src/app/call/%5Bslug%5D/page.tsx#L5).
