[{"data":1,"prerenderedAt":1202},["ShallowReactive",2],{"blog:/blog/add-realtime-to-nextjs":3},{"id":4,"title":5,"author":6,"body":7,"category":1191,"date":1192,"description":1193,"excerpt":1194,"extension":1195,"meta":1196,"navigation":100,"path":1197,"readTime":1198,"seo":1199,"stem":1200,"__hash__":1201},"blog/blog/add-realtime-to-nextjs.md","Add Realtime to a Next.js App with NoLag","Henco Burger",{"type":8,"value":9,"toc":1184},"minimark",[10,19,24,50,54,65,294,303,307,1120,1131,1135,1150,1154,1180],[11,12,13,14,18],"p",{},"Next.js renders on the server and hydrates in the browser, so the one rule for adding realtime is simple: the realtime connection belongs in a ",[15,16,17],"strong",{},"client component",". This guide shows the clean pattern, including a server route that hands the browser a token so your project key never ships to the client.",[20,21,23],"h2",{"id":22},"_1-install-the-sdk","1. Install the SDK",[25,26,31],"pre",{"className":27,"code":28,"language":29,"meta":30,"style":30},"language-bash shiki shiki-themes github-light github-dark","npm install @nolag/js-sdk\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"sScJk","npm",[35,44,46],{"class":45},"sZZnC"," install",[35,48,49],{"class":45}," @nolag/js-sdk\n",[20,51,53],{"id":52},"_2-mint-a-token-on-the-server","2. Mint a token on the server",[11,55,56,57,60,61,64],{},"Never put a project key in browser code. Add a route handler that creates a token server-side and returns it. The ",[32,58,59],{},"NOLAG_API_KEY"," (an ",[32,62,63],{},"nlg_live_..."," key) stays in your server environment.",[25,66,70],{"className":67,"code":68,"language":69,"meta":30,"style":30},"language-ts shiki shiki-themes github-light github-dark","// app/api/nolag-token/route.ts\nimport { NextResponse } from 'next/server'\n\nexport async function GET() {\n  const res = await fetch('https://api.nolag.app/v1/actors', {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${process.env.NOLAG_API_KEY}`,\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({ name: 'Web Client', actorType: 'user' }),\n  })\n\n  const actor = await res.json()\n  return NextResponse.json({ token: actor.accessToken })\n}\n","ts",[32,71,72,78,95,102,120,148,160,166,193,207,213,242,248,253,274,288],{"__ignoreMap":30},[35,73,74],{"class":37,"line":38},[35,75,77],{"class":76},"sJ8bj","// app/api/nolag-token/route.ts\n",[35,79,81,85,89,92],{"class":37,"line":80},2,[35,82,84],{"class":83},"szBVR","import",[35,86,88],{"class":87},"sVt8B"," { NextResponse } ",[35,90,91],{"class":83},"from",[35,93,94],{"class":45}," 'next/server'\n",[35,96,98],{"class":37,"line":97},3,[35,99,101],{"emptyLinePlaceholder":100},true,"\n",[35,103,105,108,111,114,117],{"class":37,"line":104},4,[35,106,107],{"class":83},"export",[35,109,110],{"class":83}," async",[35,112,113],{"class":83}," function",[35,115,116],{"class":41}," GET",[35,118,119],{"class":87},"() {\n",[35,121,123,126,130,133,136,139,142,145],{"class":37,"line":122},5,[35,124,125],{"class":83},"  const",[35,127,129],{"class":128},"sj4cs"," res",[35,131,132],{"class":83}," =",[35,134,135],{"class":83}," await",[35,137,138],{"class":41}," fetch",[35,140,141],{"class":87},"(",[35,143,144],{"class":45},"'https://api.nolag.app/v1/actors'",[35,146,147],{"class":87},", {\n",[35,149,151,154,157],{"class":37,"line":150},6,[35,152,153],{"class":87},"    method: ",[35,155,156],{"class":45},"'POST'",[35,158,159],{"class":87},",\n",[35,161,163],{"class":37,"line":162},7,[35,164,165],{"class":87},"    headers: {\n",[35,167,169,172,175,178,181,184,186,188,191],{"class":37,"line":168},8,[35,170,171],{"class":87},"      Authorization: ",[35,173,174],{"class":45},"`Bearer ${",[35,176,177],{"class":87},"process",[35,179,180],{"class":45},".",[35,182,183],{"class":87},"env",[35,185,180],{"class":45},[35,187,59],{"class":128},[35,189,190],{"class":45},"}`",[35,192,159],{"class":87},[35,194,196,199,202,205],{"class":37,"line":195},9,[35,197,198],{"class":45},"      'Content-Type'",[35,200,201],{"class":87},": ",[35,203,204],{"class":45},"'application/json'",[35,206,159],{"class":87},[35,208,210],{"class":37,"line":209},10,[35,211,212],{"class":87},"    },\n",[35,214,216,219,222,224,227,230,233,236,239],{"class":37,"line":215},11,[35,217,218],{"class":87},"    body: ",[35,220,221],{"class":128},"JSON",[35,223,180],{"class":87},[35,225,226],{"class":41},"stringify",[35,228,229],{"class":87},"({ name: ",[35,231,232],{"class":45},"'Web Client'",[35,234,235],{"class":87},", actorType: ",[35,237,238],{"class":45},"'user'",[35,240,241],{"class":87}," }),\n",[35,243,245],{"class":37,"line":244},12,[35,246,247],{"class":87},"  })\n",[35,249,251],{"class":37,"line":250},13,[35,252,101],{"emptyLinePlaceholder":100},[35,254,256,258,261,263,265,268,271],{"class":37,"line":255},14,[35,257,125],{"class":83},[35,259,260],{"class":128}," actor",[35,262,132],{"class":83},[35,264,135],{"class":83},[35,266,267],{"class":87}," res.",[35,269,270],{"class":41},"json",[35,272,273],{"class":87},"()\n",[35,275,277,280,283,285],{"class":37,"line":276},15,[35,278,279],{"class":83},"  return",[35,281,282],{"class":87}," NextResponse.",[35,284,270],{"class":41},[35,286,287],{"class":87},"({ token: actor.accessToken })\n",[35,289,291],{"class":37,"line":290},16,[35,292,293],{"class":87},"}\n",[11,295,296,297,302],{},"For production, prefer short-lived ",[298,299,301],"a",{"href":300},"/docs/client-tokens","client tokens"," minted from your project signing keys so browser sessions get scoped, expiring credentials.",[20,304,306],{"id":305},"_3-connect-from-a-client-component","3. Connect from a client component",[25,308,312],{"className":309,"code":310,"language":311,"meta":30,"style":30},"language-tsx shiki shiki-themes github-light github-dark","'use client'\nimport { useEffect, useRef, useState } from 'react'\nimport { NoLag } from '@nolag/js-sdk'\nimport type { RoomContext } from '@nolag/js-sdk'\n\n// Create the app and its `general` room first. The slug you get back has a\n// random suffix (for example `chat-a3f9`), and that suffixed slug is what\n// setApp() takes.\nconst APP_SLUG = process.env.NEXT_PUBLIC_NOLAG_APP_SLUG!\n\ntype Message = { text: string }\n\nexport default function Chat() {\n  const [messages, setMessages] = useState([] as Message[])\n  const roomRef = useRef(null as RoomContext | null)\n\n  useEffect(() => {\n    let client: ReturnType\u003Ctypeof NoLag> | undefined\n    let active = true\n\n    ;(async () => {\n      const { token } = await fetch('/api/nolag-token').then((r) => r.json())\n      if (!active) return\n\n      client = NoLag(token)\n      await client.connect()\n\n      const room = client.setApp(APP_SLUG).setRoom('general')\n      room.subscribe('message')\n      room.on\u003CMessage>('message', (data) => setMessages((m) => [...m, data]))\n      roomRef.current = room\n    })()\n\n    return () => {\n      active = false\n      roomRef.current = null\n      client?.disconnect()\n    }\n  }, [])\n\n  const send = (text: string) => {\n    const msg: Message = { text }\n    roomRef.current?.emit('message', msg)\n    // Publishers never receive their own messages, so append it locally\n    setMessages((m) => [...m, msg])\n  }\n\n  return (\n    \u003Cdiv>\n      \u003Cul>\n        {messages.map((m, i) => (\n          \u003Cli key={i}>{m.text}\u003C/li>\n        ))}\n      \u003C/ul>\n      \u003Cbutton onClick={() => send('Hello!')}>Send\u003C/button>\n    \u003C/div>\n  )\n}\n","tsx",[32,313,314,319,331,343,357,361,366,371,376,395,399,425,429,443,479,511,515,530,559,572,577,593,643,661,666,680,694,699,731,747,795,806,812,817,829,840,850,861,867,873,878,902,920,936,942,963,969,974,982,995,1006,1030,1051,1057,1067,1099,1109,1115],{"__ignoreMap":30},[35,315,316],{"class":37,"line":38},[35,317,318],{"class":45},"'use client'\n",[35,320,321,323,326,328],{"class":37,"line":80},[35,322,84],{"class":83},[35,324,325],{"class":87}," { useEffect, useRef, useState } ",[35,327,91],{"class":83},[35,329,330],{"class":45}," 'react'\n",[35,332,333,335,338,340],{"class":37,"line":97},[35,334,84],{"class":83},[35,336,337],{"class":87}," { NoLag } ",[35,339,91],{"class":83},[35,341,342],{"class":45}," '@nolag/js-sdk'\n",[35,344,345,347,350,353,355],{"class":37,"line":104},[35,346,84],{"class":83},[35,348,349],{"class":83}," type",[35,351,352],{"class":87}," { RoomContext } ",[35,354,91],{"class":83},[35,356,342],{"class":45},[35,358,359],{"class":37,"line":122},[35,360,101],{"emptyLinePlaceholder":100},[35,362,363],{"class":37,"line":150},[35,364,365],{"class":76},"// Create the app and its `general` room first. The slug you get back has a\n",[35,367,368],{"class":37,"line":162},[35,369,370],{"class":76},"// random suffix (for example `chat-a3f9`), and that suffixed slug is what\n",[35,372,373],{"class":37,"line":168},[35,374,375],{"class":76},"// setApp() takes.\n",[35,377,378,381,384,386,389,392],{"class":37,"line":195},[35,379,380],{"class":83},"const",[35,382,383],{"class":128}," APP_SLUG",[35,385,132],{"class":83},[35,387,388],{"class":87}," process.env.",[35,390,391],{"class":128},"NEXT_PUBLIC_NOLAG_APP_SLUG",[35,393,394],{"class":83},"!\n",[35,396,397],{"class":37,"line":209},[35,398,101],{"emptyLinePlaceholder":100},[35,400,401,404,407,409,412,416,419,422],{"class":37,"line":215},[35,402,403],{"class":83},"type",[35,405,406],{"class":41}," Message",[35,408,132],{"class":83},[35,410,411],{"class":87}," { ",[35,413,415],{"class":414},"s4XuR","text",[35,417,418],{"class":83},":",[35,420,421],{"class":128}," string",[35,423,424],{"class":87}," }\n",[35,426,427],{"class":37,"line":244},[35,428,101],{"emptyLinePlaceholder":100},[35,430,431,433,436,438,441],{"class":37,"line":250},[35,432,107],{"class":83},[35,434,435],{"class":83}," default",[35,437,113],{"class":83},[35,439,440],{"class":41}," Chat",[35,442,119],{"class":87},[35,444,445,447,450,453,456,459,462,465,468,471,474,476],{"class":37,"line":255},[35,446,125],{"class":83},[35,448,449],{"class":87}," [",[35,451,452],{"class":128},"messages",[35,454,455],{"class":87},", ",[35,457,458],{"class":128},"setMessages",[35,460,461],{"class":87},"] ",[35,463,464],{"class":83},"=",[35,466,467],{"class":41}," useState",[35,469,470],{"class":87},"([] ",[35,472,473],{"class":83},"as",[35,475,406],{"class":41},[35,477,478],{"class":87},"[])\n",[35,480,481,483,486,488,491,493,496,499,502,505,508],{"class":37,"line":276},[35,482,125],{"class":83},[35,484,485],{"class":128}," roomRef",[35,487,132],{"class":83},[35,489,490],{"class":41}," useRef",[35,492,141],{"class":87},[35,494,495],{"class":128},"null",[35,497,498],{"class":83}," as",[35,500,501],{"class":41}," RoomContext",[35,503,504],{"class":83}," |",[35,506,507],{"class":128}," null",[35,509,510],{"class":87},")\n",[35,512,513],{"class":37,"line":290},[35,514,101],{"emptyLinePlaceholder":100},[35,516,518,521,524,527],{"class":37,"line":517},17,[35,519,520],{"class":41},"  useEffect",[35,522,523],{"class":87},"(() ",[35,525,526],{"class":83},"=>",[35,528,529],{"class":87}," {\n",[35,531,533,536,539,541,544,547,550,553,556],{"class":37,"line":532},18,[35,534,535],{"class":83},"    let",[35,537,538],{"class":87}," client",[35,540,418],{"class":83},[35,542,543],{"class":41}," ReturnType",[35,545,546],{"class":87},"\u003C",[35,548,549],{"class":83},"typeof",[35,551,552],{"class":87}," NoLag> ",[35,554,555],{"class":83},"|",[35,557,558],{"class":128}," undefined\n",[35,560,562,564,567,569],{"class":37,"line":561},19,[35,563,535],{"class":83},[35,565,566],{"class":87}," active ",[35,568,464],{"class":83},[35,570,571],{"class":128}," true\n",[35,573,575],{"class":37,"line":574},20,[35,576,101],{"emptyLinePlaceholder":100},[35,578,580,583,586,589,591],{"class":37,"line":579},21,[35,581,582],{"class":87},"    ;(",[35,584,585],{"class":83},"async",[35,587,588],{"class":87}," () ",[35,590,526],{"class":83},[35,592,529],{"class":87},[35,594,596,599,601,604,607,609,611,613,615,618,621,624,627,630,633,635,638,640],{"class":37,"line":595},22,[35,597,598],{"class":83},"      const",[35,600,411],{"class":87},[35,602,603],{"class":128},"token",[35,605,606],{"class":87}," } ",[35,608,464],{"class":83},[35,610,135],{"class":83},[35,612,138],{"class":41},[35,614,141],{"class":87},[35,616,617],{"class":45},"'/api/nolag-token'",[35,619,620],{"class":87},").",[35,622,623],{"class":41},"then",[35,625,626],{"class":87},"((",[35,628,629],{"class":414},"r",[35,631,632],{"class":87},") ",[35,634,526],{"class":83},[35,636,637],{"class":87}," r.",[35,639,270],{"class":41},[35,641,642],{"class":87},"())\n",[35,644,646,649,652,655,658],{"class":37,"line":645},23,[35,647,648],{"class":83},"      if",[35,650,651],{"class":87}," (",[35,653,654],{"class":83},"!",[35,656,657],{"class":87},"active) ",[35,659,660],{"class":83},"return\n",[35,662,664],{"class":37,"line":663},24,[35,665,101],{"emptyLinePlaceholder":100},[35,667,669,672,674,677],{"class":37,"line":668},25,[35,670,671],{"class":87},"      client ",[35,673,464],{"class":83},[35,675,676],{"class":41}," NoLag",[35,678,679],{"class":87},"(token)\n",[35,681,683,686,689,692],{"class":37,"line":682},26,[35,684,685],{"class":83},"      await",[35,687,688],{"class":87}," client.",[35,690,691],{"class":41},"connect",[35,693,273],{"class":87},[35,695,697],{"class":37,"line":696},27,[35,698,101],{"emptyLinePlaceholder":100},[35,700,702,704,707,709,711,714,716,719,721,724,726,729],{"class":37,"line":701},28,[35,703,598],{"class":83},[35,705,706],{"class":128}," room",[35,708,132],{"class":83},[35,710,688],{"class":87},[35,712,713],{"class":41},"setApp",[35,715,141],{"class":87},[35,717,718],{"class":128},"APP_SLUG",[35,720,620],{"class":87},[35,722,723],{"class":41},"setRoom",[35,725,141],{"class":87},[35,727,728],{"class":45},"'general'",[35,730,510],{"class":87},[35,732,734,737,740,742,745],{"class":37,"line":733},29,[35,735,736],{"class":87},"      room.",[35,738,739],{"class":41},"subscribe",[35,741,141],{"class":87},[35,743,744],{"class":45},"'message'",[35,746,510],{"class":87},[35,748,750,752,755,757,760,763,765,768,771,773,775,778,780,783,785,787,789,792],{"class":37,"line":749},30,[35,751,736],{"class":87},[35,753,754],{"class":41},"on",[35,756,546],{"class":87},[35,758,759],{"class":41},"Message",[35,761,762],{"class":87},">(",[35,764,744],{"class":45},[35,766,767],{"class":87},", (",[35,769,770],{"class":414},"data",[35,772,632],{"class":87},[35,774,526],{"class":83},[35,776,777],{"class":41}," setMessages",[35,779,626],{"class":87},[35,781,782],{"class":414},"m",[35,784,632],{"class":87},[35,786,526],{"class":83},[35,788,449],{"class":87},[35,790,791],{"class":83},"...",[35,793,794],{"class":87},"m, data]))\n",[35,796,798,801,803],{"class":37,"line":797},31,[35,799,800],{"class":87},"      roomRef.current ",[35,802,464],{"class":83},[35,804,805],{"class":87}," room\n",[35,807,809],{"class":37,"line":808},32,[35,810,811],{"class":87},"    })()\n",[35,813,815],{"class":37,"line":814},33,[35,816,101],{"emptyLinePlaceholder":100},[35,818,820,823,825,827],{"class":37,"line":819},34,[35,821,822],{"class":83},"    return",[35,824,588],{"class":87},[35,826,526],{"class":83},[35,828,529],{"class":87},[35,830,832,835,837],{"class":37,"line":831},35,[35,833,834],{"class":87},"      active ",[35,836,464],{"class":83},[35,838,839],{"class":128}," false\n",[35,841,843,845,847],{"class":37,"line":842},36,[35,844,800],{"class":87},[35,846,464],{"class":83},[35,848,849],{"class":128}," null\n",[35,851,853,856,859],{"class":37,"line":852},37,[35,854,855],{"class":87},"      client?.",[35,857,858],{"class":41},"disconnect",[35,860,273],{"class":87},[35,862,864],{"class":37,"line":863},38,[35,865,866],{"class":87},"    }\n",[35,868,870],{"class":37,"line":869},39,[35,871,872],{"class":87},"  }, [])\n",[35,874,876],{"class":37,"line":875},40,[35,877,101],{"emptyLinePlaceholder":100},[35,879,881,883,886,888,890,892,894,896,898,900],{"class":37,"line":880},41,[35,882,125],{"class":83},[35,884,885],{"class":41}," send",[35,887,132],{"class":83},[35,889,651],{"class":87},[35,891,415],{"class":414},[35,893,418],{"class":83},[35,895,421],{"class":128},[35,897,632],{"class":87},[35,899,526],{"class":83},[35,901,529],{"class":87},[35,903,905,908,911,913,915,917],{"class":37,"line":904},42,[35,906,907],{"class":83},"    const",[35,909,910],{"class":128}," msg",[35,912,418],{"class":83},[35,914,406],{"class":41},[35,916,132],{"class":83},[35,918,919],{"class":87}," { text }\n",[35,921,923,926,929,931,933],{"class":37,"line":922},43,[35,924,925],{"class":87},"    roomRef.current?.",[35,927,928],{"class":41},"emit",[35,930,141],{"class":87},[35,932,744],{"class":45},[35,934,935],{"class":87},", msg)\n",[35,937,939],{"class":37,"line":938},44,[35,940,941],{"class":76},"    // Publishers never receive their own messages, so append it locally\n",[35,943,945,948,950,952,954,956,958,960],{"class":37,"line":944},45,[35,946,947],{"class":41},"    setMessages",[35,949,626],{"class":87},[35,951,782],{"class":414},[35,953,632],{"class":87},[35,955,526],{"class":83},[35,957,449],{"class":87},[35,959,791],{"class":83},[35,961,962],{"class":87},"m, msg])\n",[35,964,966],{"class":37,"line":965},46,[35,967,968],{"class":87},"  }\n",[35,970,972],{"class":37,"line":971},47,[35,973,101],{"emptyLinePlaceholder":100},[35,975,977,979],{"class":37,"line":976},48,[35,978,279],{"class":83},[35,980,981],{"class":87}," (\n",[35,983,985,988,992],{"class":37,"line":984},49,[35,986,987],{"class":87},"    \u003C",[35,989,991],{"class":990},"s9eBZ","div",[35,993,994],{"class":87},">\n",[35,996,998,1001,1004],{"class":37,"line":997},50,[35,999,1000],{"class":87},"      \u003C",[35,1002,1003],{"class":990},"ul",[35,1005,994],{"class":87},[35,1007,1009,1012,1015,1017,1019,1021,1024,1026,1028],{"class":37,"line":1008},51,[35,1010,1011],{"class":87},"        {messages.",[35,1013,1014],{"class":41},"map",[35,1016,626],{"class":87},[35,1018,782],{"class":414},[35,1020,455],{"class":87},[35,1022,1023],{"class":414},"i",[35,1025,632],{"class":87},[35,1027,526],{"class":83},[35,1029,981],{"class":87},[35,1031,1033,1036,1039,1042,1044,1047,1049],{"class":37,"line":1032},52,[35,1034,1035],{"class":87},"          \u003C",[35,1037,1038],{"class":990},"li",[35,1040,1041],{"class":41}," key",[35,1043,464],{"class":83},[35,1045,1046],{"class":87},"{i}>{m.text}\u003C/",[35,1048,1038],{"class":990},[35,1050,994],{"class":87},[35,1052,1054],{"class":37,"line":1053},53,[35,1055,1056],{"class":87},"        ))}\n",[35,1058,1060,1063,1065],{"class":37,"line":1059},54,[35,1061,1062],{"class":87},"      \u003C/",[35,1064,1003],{"class":990},[35,1066,994],{"class":87},[35,1068,1070,1072,1075,1078,1080,1083,1085,1087,1089,1092,1095,1097],{"class":37,"line":1069},55,[35,1071,1000],{"class":87},[35,1073,1074],{"class":990},"button",[35,1076,1077],{"class":41}," onClick",[35,1079,464],{"class":83},[35,1081,1082],{"class":87},"{() ",[35,1084,526],{"class":83},[35,1086,885],{"class":41},[35,1088,141],{"class":87},[35,1090,1091],{"class":45},"'Hello!'",[35,1093,1094],{"class":87},")}>Send\u003C/",[35,1096,1074],{"class":990},[35,1098,994],{"class":87},[35,1100,1102,1105,1107],{"class":37,"line":1101},56,[35,1103,1104],{"class":87},"    \u003C/",[35,1106,991],{"class":990},[35,1108,994],{"class":87},[35,1110,1112],{"class":37,"line":1111},57,[35,1113,1114],{"class":87},"  )\n",[35,1116,1118],{"class":37,"line":1117},58,[35,1119,293],{"class":87},[11,1121,1122,1123,1126,1127,1130],{},"The ",[32,1124,1125],{},"active"," flag guards against React running effects twice in development and against a connection resolving after the component unmounts. The ",[32,1128,1129],{},"send"," function appends the message to local state as well as emitting it: NoLag never delivers a message back to the actor that published it, so the sender's own text would otherwise never appear on screen.",[20,1132,1134],{"id":1133},"why-the-client-component-rule-matters","Why the client-component rule matters",[11,1136,1137,1138,1141,1142,1145,1146,1149],{},"The NoLag SDK runs in Node as well as in the browser, so this is not about where the code can execute. It is about lifecycle. A server component renders once, has no mount or unmount, and its output is serialised and hydrated in the browser, so there is nowhere for a long-lived connection to live and nothing it receives would survive hydration. Keep the ",[32,1139,1140],{},"NoLag(...)"," call inside ",[32,1143,1144],{},"useEffect"," (or an event handler) in a ",[32,1147,1148],{},"'use client'"," file and the connection opens after hydration and closes on unmount, which avoids hydration mismatches and duplicated connections.",[20,1151,1153],{"id":1152},"next-steps","Next steps",[1003,1155,1156,1164,1172],{},[1038,1157,1158,1159,1163],{},"Read the ",[298,1160,1162],{"href":1161},"/docs/getting-started","5-minute quick start"," for the full connect, subscribe, and publish flow.",[1038,1165,1166,1167,1171],{},"Skip the plumbing with the ",[298,1168,1170],{"href":1169},"/docs/high-level-sdks","chat blueprint",", which wraps rooms, typing, and presence.",[1038,1173,1174,1175,1179],{},"Building agent features into your app? See the ",[298,1176,1178],{"href":1177},"/docs/agents","AI agents"," guide.",[1181,1182,1183],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":30,"searchDepth":80,"depth":80,"links":1185},[1186,1187,1188,1189,1190],{"id":22,"depth":80,"text":23},{"id":52,"depth":80,"text":53},{"id":305,"depth":80,"text":306},{"id":1133,"depth":80,"text":1134},{"id":1152,"depth":80,"text":1153},"Integration","2026-07-30","A step-by-step guide to adding realtime messaging to a Next.js app with NoLag, including a server route that mints tokens so your API key never reaches the browser.",null,"md",{},"/blog/add-realtime-to-nextjs","7 min read",{"title":5,"description":1193},"blog/add-realtime-to-nextjs","H-HyiePHT11E8HOanHVWgfkc06xK1OFcyucZ3WoaP_s",1789869416248]