[{"data":1,"prerenderedAt":503},["ShallowReactive",2],{"navigation_docs":3,"-docs-best-practices":114,"-docs-best-practices-surround":498},[4,8,12,16,20,24,28,32,36,40,44,82,86,90,94,98,102,106,110],{"title":5,"path":6,"stem":7},"Overview","\u002Fdocs","docs\u002Findex",{"title":9,"path":10,"stem":11},"Quickstart","\u002Fdocs\u002Fquickstart","docs\u002F01.quickstart",{"title":13,"path":14,"stem":15},"Authentication and keys","\u002Fdocs\u002Fauthentication","docs\u002F02.authentication",{"title":17,"path":18,"stem":19},"Images","\u002Fdocs\u002Fimages","docs\u002F03.images",{"title":21,"path":22,"stem":23},"Texts","\u002Fdocs\u002Ftexts","docs\u002F04.texts",{"title":25,"path":26,"stem":27},"Migrating from SightEngine","\u002Fdocs\u002Fmigrating-from-sightengine","docs\u002F05.migrating-from-sightengine",{"title":29,"path":30,"stem":31},"Workflows","\u002Fdocs\u002Fworkflows","docs\u002F06.workflows",{"title":33,"path":34,"stem":35},"Responses and errors","\u002Fdocs\u002Fresponses-and-errors","docs\u002F07.responses-and-errors",{"title":37,"path":38,"stem":39},"Limits and quotas","\u002Fdocs\u002Flimits-and-quotas","docs\u002F08.limits-and-quotas",{"title":41,"path":42,"stem":43},"The journal and ref","\u002Fdocs\u002Fjournal-and-ref","docs\u002F09.journal-and-ref",{"title":45,"path":46,"stem":47,"children":48,"page":81},"Integration guides","\u002Fdocs\u002Fintegration-guides","docs\u002F10.integration-guides",[49,53,57,61,65,69,73,77],{"title":50,"path":51,"stem":52},"Node.js and TypeScript","\u002Fdocs\u002Fintegration-guides\u002Fnodejs","docs\u002F10.integration-guides\u002F1.nodejs",{"title":54,"path":55,"stem":56},"Python","\u002Fdocs\u002Fintegration-guides\u002Fpython","docs\u002F10.integration-guides\u002F2.python",{"title":58,"path":59,"stem":60},"PHP","\u002Fdocs\u002Fintegration-guides\u002Fphp","docs\u002F10.integration-guides\u002F3.php",{"title":62,"path":63,"stem":64},"Go","\u002Fdocs\u002Fintegration-guides\u002Fgo","docs\u002F10.integration-guides\u002F4.go",{"title":66,"path":67,"stem":68},"Supabase Edge Functions","\u002Fdocs\u002Fintegration-guides\u002Fsupabase-edge-functions","docs\u002F10.integration-guides\u002F5.supabase-edge-functions",{"title":70,"path":71,"stem":72},"Cloudflare Workers","\u002Fdocs\u002Fintegration-guides\u002Fcloudflare-workers","docs\u002F10.integration-guides\u002F6.cloudflare-workers",{"title":74,"path":75,"stem":76},"Nuxt and Next","\u002Fdocs\u002Fintegration-guides\u002Fnuxt-and-next","docs\u002F10.integration-guides\u002F7.nuxt-and-next",{"title":78,"path":79,"stem":80},"Moderate an AI agent","\u002Fdocs\u002Fintegration-guides\u002Fmoderate-ai-agents","docs\u002F10.integration-guides\u002F8.moderate-ai-agents",false,{"title":83,"path":84,"stem":85},"AI coding agents","\u002Fdocs\u002Fai-agents","docs\u002F11.ai-agents",{"title":87,"path":88,"stem":89},"Best practices","\u002Fdocs\u002Fbest-practices","docs\u002F12.best-practices",{"title":91,"path":92,"stem":93},"Privacy and data","\u002Fdocs\u002Fprivacy-and-data","docs\u002F13.privacy-and-data",{"title":95,"path":96,"stem":97},"API reference","\u002Fdocs\u002Fapi-reference","docs\u002F14.api-reference",{"title":99,"path":100,"stem":101},"Fraud prevention","\u002Fdocs\u002Ffraud-prevention","docs\u002F16.fraud-prevention",{"title":103,"path":104,"stem":105},"Device token and challenges","\u002Fdocs\u002Fdevice-and-challenges","docs\u002F17.device-and-challenges",{"title":107,"path":108,"stem":109},"MCP server","\u002Fdocs\u002Fmcp-server","docs\u002F18.mcp-server",{"title":111,"path":112,"stem":113},"Changelog","\u002Fdocs\u002Fchangelog","docs\u002F99.changelog",{"id":115,"title":87,"body":116,"description":491,"extension":492,"links":493,"meta":494,"navigation":495,"path":88,"seo":496,"stem":89,"__hash__":497},"docs\u002Fdocs\u002F12.best-practices.md",{"type":117,"value":118,"toc":481},"minimark",[119,124,137,141,157,192,196,222,226,241,389,399,403,423,427,448,452,463,467,477],[120,121,123],"h2",{"id":122},"call-the-api-from-your-servers-only","Call the API from your servers only",[125,126,127,128,132,133,136],"p",{},"A key is a secret. Call openshield from your backend, and give your front end the decision, not the key. The API answers a request that carries a browser ",[129,130,131],"code",{},"Origin"," header with ",[129,134,135],{},"403 forbidden",", so a call from a browser fails anyway, and a key sent to a browser is exposed.",[120,138,140],{"id":139},"fail-closed","Fail closed",[125,142,143,144,147,148,151,152,156],{},"A check can fail: a timeout, a network error, a ",[129,145,146],{},"500"," or a ",[129,149,150],{},"503",". Decide what happens to the content when it does, and make the safe choice the default: ",[153,154,155],"strong",{},"hold it"," until a person has looked at it, or until a retry has succeeded. Publishing content that was never checked is the case a moderation service exists to prevent.",[158,159,160,164,178],"ul",{},[161,162,163],"li",{},"Set a timeout on the call, 10 seconds is a good start.",[161,165,166,167,170,171,173,174,177],{},"Retry ",[129,168,169],{},"429"," and ",[129,172,150],{}," after the ",[129,175,176],{},"Retry-After"," header, at most twice.",[161,179,180,181,184,185,170,188,191],{},"Do not retry ",[129,182,183],{},"400",", ",[129,186,187],{},"413",[129,189,190],{},"415",": the content cannot be accepted as it is. Refuse it.",[120,193,195],{"id":194},"act-on-the-three-outcomes","Act on the three outcomes",[158,197,198,206,214],{},[161,199,200,205],{},[153,201,202],{},[129,203,204],{},"accept",": publish.",[161,207,208,213],{},[153,209,210],{},[129,211,212],{},"review",": hide the content from other users until a person approves it. If your product has no moderation queue, add the smallest one that fits: a flag on the row and a screen to list the flagged ones.",[161,215,216,221],{},[153,217,218],{},[129,219,220],{},"reject",": refuse the content and tell the user why.",[120,223,225],{"id":224},"choose-your-messages-by-category-id","Choose your messages by category id",[125,227,228,229,232,233,236,237,240],{},"Each reason has an ",[129,230,231],{},"id",", such as ",[129,234,235],{},"nudity"," or ",[129,238,239],{},"pii_email",". It is stable. Map it to messages you write, in your user's language:",[242,243,248],"pre",{"className":244,"code":245,"language":246,"meta":247,"style":247},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const messages: Record\u003Cstring, string> = {\n  nudity: \"This image can't be used here.\",\n  pii_email: \"Please don't share email addresses in comments.\",\n}\nconst message = messages[decision.rejectReasons[0]?.id ?? \"\"] ?? \"This content can't be published.\"\n","ts","",[129,249,250,292,314,331,337],{"__ignoreMap":247},[251,252,255,259,263,267,271,274,277,280,283,286,289],"span",{"class":253,"line":254},"line",1,[251,256,258],{"class":257},"spNyl","const",[251,260,262],{"class":261},"sTEyZ"," messages",[251,264,266],{"class":265},"sMK4o",":",[251,268,270],{"class":269},"sBMFI"," Record",[251,272,273],{"class":265},"\u003C",[251,275,276],{"class":269},"string",[251,278,279],{"class":265},",",[251,281,282],{"class":269}," string",[251,284,285],{"class":265},">",[251,287,288],{"class":265}," =",[251,290,291],{"class":265}," {\n",[251,293,295,299,301,304,308,311],{"class":253,"line":294},2,[251,296,298],{"class":297},"swJcz","  nudity",[251,300,266],{"class":265},[251,302,303],{"class":265}," \"",[251,305,307],{"class":306},"sfazB","This image can't be used here.",[251,309,310],{"class":265},"\"",[251,312,313],{"class":265},",\n",[251,315,317,320,322,324,327,329],{"class":253,"line":316},3,[251,318,319],{"class":297},"  pii_email",[251,321,266],{"class":265},[251,323,303],{"class":265},[251,325,326],{"class":306},"Please don't share email addresses in comments.",[251,328,310],{"class":265},[251,330,313],{"class":265},[251,332,334],{"class":253,"line":333},4,[251,335,336],{"class":265},"}\n",[251,338,340,342,345,348,351,354,357,361,364,367,370,373,376,379,381,383,386],{"class":253,"line":339},5,[251,341,258],{"class":257},[251,343,344],{"class":261}," message ",[251,346,347],{"class":265},"=",[251,349,350],{"class":261}," messages[decision",[251,352,353],{"class":265},".",[251,355,356],{"class":261},"rejectReasons[",[251,358,360],{"class":359},"sbssI","0",[251,362,363],{"class":261},"]",[251,365,366],{"class":265},"?.",[251,368,369],{"class":261},"id ",[251,371,372],{"class":265},"??",[251,374,375],{"class":265}," \"\"",[251,377,378],{"class":261},"] ",[251,380,372],{"class":265},[251,382,303],{"class":265},[251,384,385],{"class":306},"This content can't be published.",[251,387,388],{"class":265},"\"\n",[125,390,391,392,170,395,398],{},"The English ",[129,393,394],{},"text",[129,396,397],{},"message"," of a reason are fallbacks. Do not match on them: they can be reworded.",[120,400,402],{"id":401},"send-what-you-need-to-send","Send what you need to send",[158,404,405,411,417],{},[161,406,407,410],{},[153,408,409],{},"Downscale large photos"," to about 1,280 pixels on the longer side: the upload is smaller and faster. Keep the full size of screenshots, where small text or a QR code matters.",[161,412,413,416],{},[153,414,415],{},"Send each image once."," Cache the decision with your own record of the content.",[161,418,419,422],{},[153,420,421],{},"Check what other people see."," Posts, comments, messages, profile pictures, display names, bios, listings and reviews: anything a user can publish.",[120,424,426],{"id":425},"keep-a-trail","Keep a trail",[158,428,429,441],{},[161,430,431,432,435,436,440],{},"Send a ",[129,433,434],{},"ref",", your own opaque id for the content, so you can find its decision in the ",[437,438,439],"a",{"href":42},"journal",". Do not put personal data in it.",[161,442,443,444,447],{},"Log the ",[129,445,446],{},"request_id"," of every answer next to your own record.",[120,449,451],{"id":450},"keys-and-workflows","Keys and workflows",[158,453,454,457,460],{},[161,455,456],{},"Give each service its own key, with the narrowest scope and workflows it needs.",[161,458,459],{},"Rotate keys with a grace delay, so a deploy never has a gap.",[161,461,462],{},"Use one workflow per product surface when the rules differ: stricter for a children's section, more lenient for a private chat.",[120,464,466],{"id":465},"test-without-the-network","Test without the network",[125,468,469,470,184,472,184,474,476],{},"Stub the HTTP call in your tests, and assert what your code does for ",[129,471,204],{},[129,473,212],{},[129,475,220],{}," and each kind of error. Do not call the real API from a test suite: it counts against your quota.",[478,479,480],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}",{"title":247,"searchDepth":294,"depth":294,"links":482},[483,484,485,486,487,488,489,490],{"id":122,"depth":294,"text":123},{"id":139,"depth":294,"text":140},{"id":194,"depth":294,"text":195},{"id":224,"depth":294,"text":225},{"id":401,"depth":294,"text":402},{"id":425,"depth":294,"text":426},{"id":450,"depth":294,"text":451},{"id":465,"depth":294,"text":466},"Server-side only, fail closed, downscale images, and show users messages you choose by category id.","md",null,{},true,{"title":87,"description":491},"58ytn1iuwTklZgnrSmg9-N8M07LxRJIUzwL2jlVrHP0",[499,501],{"title":83,"path":84,"stem":85,"description":500,"children":-1},"Hand the integration to your coding agent with a ready prompt, llms.txt and the OpenAPI document.",{"title":91,"path":92,"stem":93,"description":502,"children":-1},"What openshield stores and what it never stores, where, and for how long.",1792938462557]