Error Creating View from API route

ChrisBB Member
edited March 2023 in Q&A

Hello fellow dailyCo workers,

I am working on a NextJs app, and following the guide here: Use Next.js API routes to create Daily video chat rooms. However, a call to the API returned this error. I have done a lot of searching online to find an answer to no avail. Here is the error and related file contents:

error - SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
    at JSON.parse (<anonymous>)
    at packageData (node:internal/deps/undici/undici:6456:23)
    at specConsumeBody (node:internal/deps/undici/undici:6434:14)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async handler (webpack-internal:///(api)/./pages/api/room/index.js:26:26)
    at async Object.apiResolver (path-to-local-dir)
    at async DevServer.runApi (path-to-local-dir)
    at async Object.fn (path-to-local-dir)
    at async Router.execute (path-to-local-dir)
    at async (path-to-local-dir) {
  page: '/api/room'

Here is what my api file looks like:

export default async function handler(req, res) {
  if (req.method === "POST") {
    const options = {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.DAILY_API_KEY}`,
      body: JSON.stringify({
        properties: {
          enable_prejoin_ui: true,
          enable_network_ui: true,
          enable_screenshare: true,
          enable_chat: true,
          exp: Math.round( / 1000) + 300,
          eject_at_room_exp: true,

    const dailyRes = await fetch(`${process.env.DAILY_DOMAIN}/rooms`, options);

    const response = await dailyRes.json();

    if (response.error) {
      return res.status(500).json(response.error);

    return res.status(200).json(response);

  return res.status(500);

Please note that the API_KEY and DOMAIN from my env file is exactly as it is shown here. Can someone help? Thanks in advance


Best Answer

  • daily_joey
    daily_joey Moderator, Dailynista admin
    Answer ✓

    Hey @ChrisBB ,

    Can you confirm the value of the variable DAILY_DOMAIN ?

    In the example from the page you linked, there's a minor difference around the endpoint URL:

    const dailyRes = await fetch(

    In this case, the URL for DAILY_REST_DOMAIN would be and not the Daily subdomain chosen during account creation.

    API requests are made to, while room URLs contain your subdomain.


  • @daily_joey - Thanks for the prompt response, and suggestion. I was using rather thank the one above. The fix is in - thanks. However, I have another issue - there are two instances of the video player. I was expecting just one (please see the attached image)

    How can I resolve this?

  • daily_joey
    daily_joey Moderator, Dailynista admin

    @ChrisBB it's hard to say without seeing the code for your client implementation but it seems like you might be instantiating the Daily Prebuilt iFrame multiple times unintentionally.

    A typical call flow might create the frame and join(), then at the end of a session leave() then destroy() to clean up the iFrame created by Daily. If you can share a code snippet that includes the createFrame method and how it is called, we can take a look.

  • Hello @daily_joey , Thanks again for the prompt response. Below is a copy of the code :

    import Call from "./Call";
    import Home from "./Home";
    import { useState } from "react";
    export default function ActivePool({ id, isConfigured = false }) {
      const [room, setRoom] = useState(null);
      const [expiry, setExpiry] = useState(null);
      const [callFrame, setCallFrame] = useState(null);
      return (
          <div className="min-h-full">
            <main className="py-10">
              <div className="mx-auto mt-8 grid max-w-3xl grid-cols-1 gap-6 sm:px-6 lg:max-w-7xl lg:grid-flow-col-dense lg:grid-cols-1">
                <div className="space-y-6 lg:col-span-2 lg:col-start-1">
                  {/* Video section*/}
                  <section aria-labelledby="applicant-information-title">
                    <div className="bg-white shadow sm:rounded-lg">
                      <div className="border-t border-gray-200 px-4 py-5 sm:px-6">
                        <dl className="grid grid-cols-1 gap-x-4 gap-y-8 sm:grid-cols-2">
                          <div className="sm:col-span-2">
                            <dt className="text-sm font-medium text-gray-500">
                            <dd className="mt-1 text-sm text-gray-900">
                              {/* Video Lives here */}
                              {room ? (
                              ) : (

    I'm thinking that it's rendering cos of the Call/Home, but that came from the Next.js snippet from one of your tutorials. Please advice how to restructure this

  • Hello @daily_joey , My last question was flagged for some reason, but Tasha from your team unflagged it. Should I expect a response today. Thanks. Also, please keep in mind that I am using NextJS framework. Can you explain how to use the .join as I cant find any tutorial on using with the framework. Thanks in advance.

  • ChrisBB
    ChrisBB Member
    edited March 2023

    Your tutorial on this page ( is poorly written. I am getting an error `ReferenceError: useCallback is not defined` via `components/Call.js` following the steps from the docs. A few other lines of codes could have been written better, more clearly as well. Sorry for venting my frustrations on the thread.

  • Along with the above code snippet (march 19th), here is the code for the Call component:

    import { useCallback, useEffect, useRef, useState } from "react";
    // import Button from "@custom/shared/components/Button";
    // import {
    //   Card,
    //   CardBody,
    //   CardHeader,
    //   CardFooter,
    // } from "@custom/shared/components/Card";
    // import { TextInput } from "@custom/shared/components/Input";
    import DailyIframe from "@daily-co/daily-js";
    import { writeText } from "clipboard-polyfill";
    import ExpiryTimer from "./ExpiryTimer";
    const CALL_OPTIONS = {
      showLeaveButton: true,
      iframeStyle: {
        height: "100%",
        width: "100%",
        aspectRatio: 16 / 9,
        minwidth: "400px",
        maxWidth: "920px",
        border: "0",
        borderRadius: "12px",
    export function Call({ room, setRoom, callFrame, setCallFrame, expiry }) {
      const callRef = useRef(null);
      const [isLinkCopied, setIsLinkCopied] = useState(false);
      const handleCopyClick = useCallback(() => {
        setTimeout(() => setIsLinkCopied(false), 5000);
      }, [room, isLinkCopied]);
      const createAndJoinCall = useCallback(() => {
        const newCallFrame = DailyIframe.createFrame(
        newCallFrame.join({ url: room });
        const leaveCall = () => {
        newCallFrame.on("left-meeting", leaveCall);
      }, [room, setCallFrame]);
       * Initiate Daily iframe creation on component render if it doesn't already exist
      useEffect(() => {
        if (callFrame) return;
      }, [callFrame, createAndJoinCall]);
      return (
          <div className="call-container">
            {/* Daily iframe container */}
            <div ref={callRef} className="call" />
              <div>Copy and share the URL to invite others</div>
                <label htmlFor="copy-url"></label>
                  placeholder="Copy this room URL"
                <button onClick={handleCopyClick}>
                  {isLinkCopied ? "Copied!" : `Copy room URL`}
                {expiry && (
                    Room expires in:
                    <ExpiryTimer expiry={expiry} />
            <style jsx>{`
              .call-container {
                display: flex;
                align-items: center;
                gap: var(--spacing-md);
              .call-container :global(.call) {
                width: 100%;
              .call-container :global(.button) {
                margin-top: var(--spacing-md);
              .call-container :global(.card) {
                max-width: 300px;
                max-height: 400px;
              .call-container :global(.card-footer) {
                align-items: center;
                gap: var(--spacing-xxs);
              .call-container :global(.countdown) {
                position: static;
                border-radius: var(--radius-sm);
              @media only screen and (max-width: 750px) {
                .call-container {
                  flex-direction: column;
    export default Call;

    The issue again is that the call video is displaying twice on the page

  • daily_joey
    daily_joey Moderator, Dailynista admin

    Hi @ChrisBB , thanks for the additional code - it looks like everything should be working, so I've asked my teammates to take a look. We'll also work on reviewing the demo you've been referencing, as it's one of our older ones.

  • Hello Joey,

    Please circle back with response from your team. Thank you for your support