[{"data":1,"prerenderedAt":844},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fnodejs-quickstart":3,"docs-nav":830},{"id":4,"title":5,"body":6,"description":822,"extension":823,"meta":824,"navigation":131,"order":152,"path":825,"section":826,"seo":827,"stem":828,"__hash__":829},"docs\u002Fdocs\u002Fnodejs-quickstart.md","Node.js",{"type":7,"value":8,"toc":806},"minimark",[9,14,18,21,33,37,65,69,96,100,107,184,187,195,198,207,217,221,224,247,262,295,299,302,305,327,330,343,346,355,362,366,373,395,398,413,426,430,435,441,483,487,501,554,557,581,584,588,594,665,668,712,719,730,734,749,763,769,773,802],[10,11,13],"h2",{"id":12},"overview","Overview",[15,16,17],"p",{},"This guide adds BlockBots to a Node.js server. You will install one package and mount one middleware — detection then runs on every request before your routes do.",[15,19,20],{},"It takes about five minutes. No dependencies, no database, no build step.",[22,23,24],"blockquote",{},[15,25,26,27,32],{},"This guide covers server-side protection. If your pages are rendered entirely in the browser, see the ",[28,29,31],"a",{"href":30},"\u002Fdocs\u002Fjavascript-quickstart","JavaScript guide",". The two work together.",[10,34,36],{"id":35},"prerequisites","Prerequisites",[38,39,40,49,62],"ul",{},[41,42,43,44,48],"li",{},"Node ",[45,46,47],"strong",{},"18"," or higher",[41,50,51,52,58,59],{},"An API key — create one at ",[28,53,57],{"href":54,"rel":55},"https:\u002F\u002Fpanel.blockbots.org",[56],"nofollow","panel.blockbots.org"," under ",[45,60,61],{},"Settings → API Keys",[41,63,64],{},"The domain registered on that key, exactly as visitors reach it",[10,66,68],{"id":67},"step-1-install","Step 1 — Install",[70,71,77],"pre",{"className":72,"code":73,"filename":74,"language":75,"meta":76,"style":76},"language-bash shiki shiki-themes github-dark-dimmed","npm install @blockbots\u002Fnode\n","terminal","bash","",[78,79,80],"code",{"__ignoreMap":76},[81,82,85,89,93],"span",{"class":83,"line":84},"line",1,[81,86,88],{"style":87},"--shiki-default:#F69D50","npm",[81,90,92],{"style":91},"--shiki-default:#96D0FF"," install",[81,94,95],{"style":91}," @blockbots\u002Fnode\n",[10,97,99],{"id":98},"step-2-mount-the-middleware","Step 2 — Mount the middleware",[15,101,102,103,106],{},"Add it ",[45,104,105],{},"before your routes",":",[70,108,113],{"className":109,"code":110,"filename":111,"language":112,"meta":76,"style":76},"language-js shiki shiki-themes github-dark-dimmed","const express = require('express');\nconst blockbots = require('@blockbots\u002Fnode');\n\nconst app = express();\n\napp.use(blockbots({\n  apiKey: 'YOUR_API_KEY',\n}));\n\napp.get('\u002F', (req, res) => res.send('Welcome'));\n\napp.listen(3000);\n","server.js","js",[78,114,115,120,126,133,139,144,150,156,162,167,173,178],{"__ignoreMap":76},[81,116,117],{"class":83,"line":84},[81,118,119],{},"const express = require('express');\n",[81,121,123],{"class":83,"line":122},2,[81,124,125],{},"const blockbots = require('@blockbots\u002Fnode');\n",[81,127,129],{"class":83,"line":128},3,[81,130,132],{"emptyLinePlaceholder":131},true,"\n",[81,134,136],{"class":83,"line":135},4,[81,137,138],{},"const app = express();\n",[81,140,142],{"class":83,"line":141},5,[81,143,132],{"emptyLinePlaceholder":131},[81,145,147],{"class":83,"line":146},6,[81,148,149],{},"app.use(blockbots({\n",[81,151,153],{"class":83,"line":152},7,[81,154,155],{},"  apiKey: 'YOUR_API_KEY',\n",[81,157,159],{"class":83,"line":158},8,[81,160,161],{},"}));\n",[81,163,165],{"class":83,"line":164},9,[81,166,132],{"emptyLinePlaceholder":131},[81,168,170],{"class":83,"line":169},10,[81,171,172],{},"app.get('\u002F', (req, res) => res.send('Welcome'));\n",[81,174,176],{"class":83,"line":175},11,[81,177,132],{"emptyLinePlaceholder":131},[81,179,181],{"class":83,"line":180},12,[81,182,183],{},"app.listen(3000);\n",[15,185,186],{},"There is nothing to call. The middleware decides on its own and answers the requests it stops.",[22,188,189],{},[15,190,191,194],{},[45,192,193],{},"Order matters."," A middleware mounted after your routes never sees a request the router has already answered, so nothing is protected. It writes a line to your log when that happens, so check there if nothing seems to happen.",[15,196,197],{},"Read the key from the environment instead of hard-coding it:",[70,199,201],{"className":109,"code":200,"filename":111,"language":112,"meta":76,"style":76},"app.use(blockbots({ apiKey: process.env.BLOCKBOTS_API_KEY }));\n",[78,202,203],{"__ignoreMap":76},[81,204,205],{"class":83,"line":84},[81,206,200],{},[15,208,209,212,213,216],{},[78,210,211],{},"BLOCKBOTS_API_KEY"," is picked up automatically, so ",[78,214,215],{},"blockbots()"," with no arguments also works when that variable is set.",[10,218,220],{"id":219},"step-3-exclude-what-must-not-be-checked","Step 3 — Exclude what must not be checked",[15,222,223],{},"Health checks, webhooks and your own API routes should go straight through:",[70,225,227],{"className":109,"code":226,"filename":111,"language":112,"meta":76,"style":76},"app.use(blockbots({\n  apiKey: process.env.BLOCKBOTS_API_KEY,\n  exclude: ['\u002Fhealthz', '\u002Fwebhooks', '\u002Fapi'],\n}));\n",[78,228,229,233,238,243],{"__ignoreMap":76},[81,230,231],{"class":83,"line":84},[81,232,149],{},[81,234,235],{"class":83,"line":122},[81,236,237],{},"  apiKey: process.env.BLOCKBOTS_API_KEY,\n",[81,239,240],{"class":83,"line":128},[81,241,242],{},"  exclude: ['\u002Fhealthz', '\u002Fwebhooks', '\u002Fapi'],\n",[81,244,245],{"class":83,"line":135},[81,246,161],{},[15,248,249,250,253,254,257,258,261],{},"A string matches that path and everything under it — ",[78,251,252],{},"\u002Fapi"," covers ",[78,255,256],{},"\u002Fapi\u002Fusers",", but not ",[78,259,260],{},"\u002Fapi-docs",". Regular expressions and functions work too:",[70,263,265],{"className":109,"code":264,"filename":111,"language":112,"meta":76,"style":76},"exclude: [\n  '\u002Fwebhooks',                               \u002F\u002F path and everything under it\n  \u002F^\\\u002Fadmin\\\u002F\u002F,                              \u002F\u002F regular expression\n  (req) => req.headers['x-internal'] === '1' \u002F\u002F your own rule\n]\n",[78,266,267,272,280,285,290],{"__ignoreMap":76},[81,268,269],{"class":83,"line":84},[81,270,271],{},"exclude: [\n",[81,273,274,277],{"class":83,"line":122},[81,275,276],{},"  '\u002Fwebhooks',",[81,278,279],{},"                               \u002F\u002F path and everything under it\n",[81,281,282],{"class":83,"line":128},[81,283,284],{},"  \u002F^\\\u002Fadmin\\\u002F\u002F,                              \u002F\u002F regular expression\n",[81,286,287],{"class":83,"line":135},[81,288,289],{},"  (req) => req.headers['x-internal'] === '1' \u002F\u002F your own rule\n",[81,291,292],{"class":83,"line":141},[81,293,294],{},"]\n",[10,296,298],{"id":297},"step-4-check-it-works","Step 4 — Check it works",[15,300,301],{},"Open your site in a private window. You should see a verification screen for a second, then your own page.",[15,303,304],{},"To confirm what is going on under the hood, switch on the self-test:",[70,306,308],{"className":109,"code":307,"filename":111,"language":112,"meta":76,"style":76},"app.use(blockbots({\n  apiKey: process.env.BLOCKBOTS_API_KEY,\n  selftest: 'pick-a-long-secret',\n}));\n",[78,309,310,314,318,323],{"__ignoreMap":76},[81,311,312],{"class":83,"line":84},[81,313,149],{},[81,315,316],{"class":83,"line":122},[81,317,237],{},[81,319,320],{"class":83,"line":128},[81,321,322],{},"  selftest: 'pick-a-long-secret',\n",[81,324,325],{"class":83,"line":135},[81,326,161],{},[15,328,329],{},"Then request any page with that secret:",[70,331,333],{"className":72,"code":332,"filename":74,"language":75,"meta":76,"style":76},"curl \"https:\u002F\u002Fyour-site.com\u002F?bb-selftest=pick-a-long-secret\"\n",[78,334,335],{"__ignoreMap":76},[81,336,337,340],{"class":83,"line":84},[81,338,339],{"style":87},"curl",[81,341,342],{"style":91}," \"https:\u002F\u002Fyour-site.com\u002F?bb-selftest=pick-a-long-secret\"\n",[15,344,345],{},"A healthy install answers like this:",[70,347,353],{"className":348,"code":350,"filename":351,"language":352,"meta":76},[349],"language-text","Blockbots self-test\n\nenvironment\n  node                   v20.11.0\n  platform               generic (has a socket)\n  ed25519                yes\n  library active         yes\n  enabled option         true\n  service state          ok\n\nthis request\n  socket address         203.0.113.9\n  trusted proxy          NO\n  resolved client ip     203.0.113.9\n  ip came from           socket\n  looks like a browser   yes\n  navigation             yes\n  host                   your-site.com\n  path excluded          NO\n\ntoken\n  __bbjwt cookie         absent - visitor has not been verified yet\n\ncache\n  store                  memory\n  entries                14\n  ttl                    3600s\n\napi\n  url                    https:\u002F\u002Fapi.blockbots.org\u002Fv1\u002Fverify-bot\n  round trip             86 ms\n  reachable              yes\n  answered               not_bot\n","output","text",[78,354,350],{"__ignoreMap":76},[15,356,357,358,361],{},"Nothing secret is printed — not your API key, not the visitor's token. Remove the ",[78,359,360],{},"selftest"," option when you are done; without it the page does not exist.",[10,363,365],{"id":364},"step-5-if-you-use-a-cdn-or-reverse-proxy","Step 5 — If you use a CDN or reverse proxy",[15,367,368,369,372],{},"Cloudflare is recognised automatically, and so are nginx, Docker and a load balancer on your own network. ",[45,370,371],{},"Any other CDN needs one line",", otherwise every visitor arrives as the same address and nobody can pass verification:",[70,374,376],{"className":109,"code":375,"filename":111,"language":112,"meta":76,"style":76},"app.use(blockbots({\n  apiKey: process.env.BLOCKBOTS_API_KEY,\n  trustedProxies: '203.0.113.0\u002F24,198.51.100.7',\n}));\n",[78,377,378,382,386,391],{"__ignoreMap":76},[81,379,380],{"class":83,"line":84},[81,381,149],{},[81,383,384],{"class":83,"line":122},[81,385,237],{},[81,387,388],{"class":83,"line":128},[81,389,390],{},"  trustedProxies: '203.0.113.0\u002F24,198.51.100.7',\n",[81,392,393],{"class":83,"line":135},[81,394,161],{},[15,396,397],{},"Use the address ranges your CDN connects from — your provider publishes them.",[15,399,400,401,404,405,408,409,412],{},"In the self-test, ",[78,402,403],{},"trusted proxy"," should read ",[78,406,407],{},"yes"," and ",[78,410,411],{},"resolved client ip"," should be the visitor's real address, not your CDN's.",[22,414,415],{},[15,416,417,418,421,422,425],{},"Express's own ",[78,419,420],{},"app.set('trust proxy', …)"," does not affect BlockBots. Use ",[78,423,424],{},"trustedProxies",".",[10,427,429],{"id":428},"step-6-other-frameworks","Step 6 — Other frameworks",[431,432,434],"h3",{"id":433},"fastify","Fastify",[15,436,437,438,106],{},"Fastify runs Connect-style middleware through ",[78,439,440],{},"@fastify\u002Fmiddie",[70,442,444],{"className":109,"code":443,"filename":111,"language":112,"meta":76,"style":76},"const fastify = require('fastify')();\nconst blockbots = require('@blockbots\u002Fnode');\n\nawait fastify.register(require('@fastify\u002Fmiddie'));\nfastify.use(blockbots({ apiKey: process.env.BLOCKBOTS_API_KEY }));\n\nfastify.get('\u002F', async () => 'Welcome');\nawait fastify.listen({ port: 3000 });\n",[78,445,446,451,455,459,464,469,473,478],{"__ignoreMap":76},[81,447,448],{"class":83,"line":84},[81,449,450],{},"const fastify = require('fastify')();\n",[81,452,453],{"class":83,"line":122},[81,454,125],{},[81,456,457],{"class":83,"line":128},[81,458,132],{"emptyLinePlaceholder":131},[81,460,461],{"class":83,"line":135},[81,462,463],{},"await fastify.register(require('@fastify\u002Fmiddie'));\n",[81,465,466],{"class":83,"line":141},[81,467,468],{},"fastify.use(blockbots({ apiKey: process.env.BLOCKBOTS_API_KEY }));\n",[81,470,471],{"class":83,"line":146},[81,472,132],{"emptyLinePlaceholder":131},[81,474,475],{"class":83,"line":152},[81,476,477],{},"fastify.get('\u002F', async () => 'Welcome');\n",[81,479,480],{"class":83,"line":158},[81,481,482],{},"await fastify.listen({ port: 3000 });\n",[431,484,486],{"id":485},"nextjs","Next.js",[15,488,489,490,493,494,497,498,106],{},"Next.js middleware runs on a Web ",[78,491,492],{},"Request",", so use ",[78,495,496],{},"check()"," with ",[78,499,500],{},"toResponse()",[70,502,505],{"className":109,"code":503,"filename":504,"language":112,"meta":76,"style":76},"import { createBlockbots, toResponse } from '@blockbots\u002Fnode';\n\nconst bb = createBlockbots({ apiKey: process.env.BLOCKBOTS_API_KEY });\n\nexport async function middleware(request) {\n  const decision = await bb.check(request);\n  if (!decision.allow) return toResponse(decision);\n}\n\nexport const config = { matcher: ['\u002F((?!_next|favicon.ico).*)'] };\n","middleware.js",[78,506,507,512,516,521,525,530,535,540,545,549],{"__ignoreMap":76},[81,508,509],{"class":83,"line":84},[81,510,511],{},"import { createBlockbots, toResponse } from '@blockbots\u002Fnode';\n",[81,513,514],{"class":83,"line":122},[81,515,132],{"emptyLinePlaceholder":131},[81,517,518],{"class":83,"line":128},[81,519,520],{},"const bb = createBlockbots({ apiKey: process.env.BLOCKBOTS_API_KEY });\n",[81,522,523],{"class":83,"line":135},[81,524,132],{"emptyLinePlaceholder":131},[81,526,527],{"class":83,"line":141},[81,528,529],{},"export async function middleware(request) {\n",[81,531,532],{"class":83,"line":146},[81,533,534],{},"  const decision = await bb.check(request);\n",[81,536,537],{"class":83,"line":152},[81,538,539],{},"  if (!decision.allow) return toResponse(decision);\n",[81,541,542],{"class":83,"line":158},[81,543,544],{},"}\n",[81,546,547],{"class":83,"line":164},[81,548,132],{"emptyLinePlaceholder":131},[81,550,551],{"class":83,"line":169},[81,552,553],{},"export const config = { matcher: ['\u002F((?!_next|favicon.ico).*)'] };\n",[15,555,556],{},"Vercel, Cloudflare Workers, Netlify and Deno Deploy work as-is — each is recognised from its own environment. Anywhere else there is no connection to read the visitor's address from, so name the header your platform sets:",[70,558,560],{"className":109,"code":559,"filename":504,"language":112,"meta":76,"style":76},"const bb = createBlockbots({\n  apiKey: process.env.BLOCKBOTS_API_KEY,\n  clientIp: 'x-real-ip',\n});\n",[78,561,562,567,571,576],{"__ignoreMap":76},[81,563,564],{"class":83,"line":84},[81,565,566],{},"const bb = createBlockbots({\n",[81,568,569],{"class":83,"line":122},[81,570,237],{},[81,572,573],{"class":83,"line":128},[81,574,575],{},"  clientIp: 'x-real-ip',\n",[81,577,578],{"class":83,"line":135},[81,579,580],{},"});\n",[15,582,583],{},"Without it protection switches itself off for those requests and says so in your log — deliberately, because a cookie with no address to bind to would send every visitor back to the verification page forever.",[431,585,587],{"id":586},"koa-hapi-and-everything-else","Koa, Hapi and everything else",[15,589,590,591,593],{},"Use ",[78,592,496],{},". It reads the request and gives you a verdict without touching the response, so you decide what happens:",[70,595,597],{"className":109,"code":596,"filename":504,"language":112,"meta":76,"style":76},"const { createBlockbots } = require('@blockbots\u002Fnode');\n\nconst bb = createBlockbots({ apiKey: process.env.BLOCKBOTS_API_KEY });\n\n\u002F\u002F Koa\napp.use(async (ctx, next) => {\n  const decision = await bb.check(ctx.req);\n\n  if (decision.allow) return next();\n\n  ctx.status = decision.response.status;\n  ctx.set(decision.response.headers);\n  ctx.body = decision.response.body;\n});\n",[78,598,599,604,608,612,616,621,626,631,635,640,644,649,654,660],{"__ignoreMap":76},[81,600,601],{"class":83,"line":84},[81,602,603],{},"const { createBlockbots } = require('@blockbots\u002Fnode');\n",[81,605,606],{"class":83,"line":122},[81,607,132],{"emptyLinePlaceholder":131},[81,609,610],{"class":83,"line":128},[81,611,520],{},[81,613,614],{"class":83,"line":135},[81,615,132],{"emptyLinePlaceholder":131},[81,617,618],{"class":83,"line":141},[81,619,620],{},"\u002F\u002F Koa\n",[81,622,623],{"class":83,"line":146},[81,624,625],{},"app.use(async (ctx, next) => {\n",[81,627,628],{"class":83,"line":152},[81,629,630],{},"  const decision = await bb.check(ctx.req);\n",[81,632,633],{"class":83,"line":158},[81,634,132],{"emptyLinePlaceholder":131},[81,636,637],{"class":83,"line":164},[81,638,639],{},"  if (decision.allow) return next();\n",[81,641,642],{"class":83,"line":169},[81,643,132],{"emptyLinePlaceholder":131},[81,645,646],{"class":83,"line":175},[81,647,648],{},"  ctx.status = decision.response.status;\n",[81,650,651],{"class":83,"line":180},[81,652,653],{},"  ctx.set(decision.response.headers);\n",[81,655,657],{"class":83,"line":656},13,[81,658,659],{},"  ctx.body = decision.response.body;\n",[81,661,663],{"class":83,"line":662},14,[81,664,580],{},[15,666,667],{},"What you get back:",[70,669,671],{"className":109,"code":670,"language":112,"meta":76,"style":76},"{\n  action: 'allow',          \u002F\u002F 'allow' | 'block' | 'challenge'\n  allow: true,              \u002F\u002F the one field most code needs\n  reason: 'token_valid',    \u002F\u002F why, for your logs\n  ip: '203.0.113.9',        \u002F\u002F the resolved client address\n  ua: 'Mozilla\u002F5.0 …',\n  response: { … }           \u002F\u002F the page to send, on 'block' and 'challenge'\n}\n",[78,672,673,678,683,688,693,698,703,708],{"__ignoreMap":76},[81,674,675],{"class":83,"line":84},[81,676,677],{},"{\n",[81,679,680],{"class":83,"line":122},[81,681,682],{},"  action: 'allow',          \u002F\u002F 'allow' | 'block' | 'challenge'\n",[81,684,685],{"class":83,"line":128},[81,686,687],{},"  allow: true,              \u002F\u002F the one field most code needs\n",[81,689,690],{"class":83,"line":135},[81,691,692],{},"  reason: 'token_valid',    \u002F\u002F why, for your logs\n",[81,694,695],{"class":83,"line":141},[81,696,697],{},"  ip: '203.0.113.9',        \u002F\u002F the resolved client address\n",[81,699,700],{"class":83,"line":146},[81,701,702],{},"  ua: 'Mozilla\u002F5.0 …',\n",[81,704,705],{"class":83,"line":152},[81,706,707],{},"  response: { … }           \u002F\u002F the page to send, on 'block' and 'challenge'\n",[81,709,710],{"class":83,"line":158},[81,711,544],{},[15,713,714,715,718],{},"Send ",[78,716,717],{},"response"," as-is and the flow works exactly as with the middleware. Ignore it and nothing is enforced — useful if you only want to log at first.",[15,720,721,722,725,726,729],{},"The middleware also leaves this object on ",[78,723,724],{},"req.blockbots",", so a route behind it can read ",[78,727,728],{},"req.blockbots.ip"," without doing the work again.",[10,731,733],{"id":732},"how-it-works","How it works",[735,736,737,740,746],"ol",{},[41,738,739],{},"A visitor with a valid cookie passes through instantly — no network call.",[41,741,742,743,425],{},"Anything that does not look like a browser is checked against the cloud. Crawlers you allow, such as Googlebot, get your content; impostors using their name get ",[78,744,745],{},"403",[41,747,748],{},"Everyone else sees the verification page, gets a signed cookie, and the page reloads.",[15,750,751,752,408,755,758,759,762],{},"Verdicts are cached, so a crawler costs one cloud call per hour rather than one per page. ",[78,753,754],{},"fetch",[78,756,757],{},"XHR"," requests are never interrupted, and ",[78,760,761],{},"POST"," bodies are never swallowed. If the cloud is unreachable, the middleware steps aside and your site keeps serving.",[15,764,765,768],{},[45,766,767],{},"A dead or expired key never reaches your visitors."," Before the verification page is served for the first time, BlockBots asks whether the cloud is serving your key at all. A rejection switches protection off for five minutes rather than handing out a page whose script would fail the same way and never reload — so a lapsed subscription leaves your site unprotected, not broken. The answer is cached, so this costs one request an hour, not one per visitor, and renewing a subscription takes effect on its own with no restart.",[10,770,772],{"id":771},"next-steps","Next steps",[38,774,775,781,788,795],{},[41,776,777,780],{},[28,778,779],{"href":30},"JavaScript"," — add the browser SDK alongside this",[41,782,783,787],{},[28,784,786],{"href":785},"\u002Fdocs\u002Fpython-quickstart","Python"," — the same protection for Django or FastAPI",[41,789,790,794],{},[28,791,793],{"href":792},"\u002Fdocs\u002Fgolang-quickstart","Go"," — the same protection for a net\u002Fhttp server",[41,796,797,801],{},[28,798,800],{"href":799},"\u002Fdocs\u002Fphp-quickstart","PHP"," — the same protection for a PHP site",[803,804,805],"style",{},"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);}",{"title":76,"searchDepth":122,"depth":122,"links":807},[808,809,810,811,812,813,814,815,820,821],{"id":12,"depth":122,"text":13},{"id":35,"depth":122,"text":36},{"id":67,"depth":122,"text":68},{"id":98,"depth":122,"text":99},{"id":219,"depth":122,"text":220},{"id":297,"depth":122,"text":298},{"id":364,"depth":122,"text":365},{"id":428,"depth":122,"text":429,"children":816},[817,818,819],{"id":433,"depth":128,"text":434},{"id":485,"depth":128,"text":486},{"id":586,"depth":128,"text":587},{"id":732,"depth":122,"text":733},{"id":771,"depth":122,"text":772},"Protect an Express, Fastify, Koa or Next.js site from bots with one middleware — no dependencies.","md",{},"\u002Fdocs\u002Fnodejs-quickstart","Server",{"title":5,"description":822},"docs\u002Fnodejs-quickstart","Lzohl8OUxSjb6CyuhM6UK7qlLcO39soQNIjjC6pQCE0",[831,835,837,838,841,842,843],{"title":832,"path":833,"order":84,"section":834},"Getting Started","\u002Fdocs\u002Fgetting-started","Getting started",{"title":779,"path":30,"order":122,"section":836},"Web",{"title":800,"path":799,"order":135,"section":826},{"title":839,"path":840,"order":141,"section":826},"WordPress Plugin","\u002Fdocs\u002Fwordpress-plugin",{"title":5,"path":825,"order":152,"section":826},{"title":786,"path":785,"order":164,"section":826},{"title":793,"path":792,"order":169,"section":826},1794295237813]