From d3f464c9170168857ffea7649237bd38d865015b Mon Sep 17 00:00:00 2001
From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com>
Date: Fri, 19 Jun 2026 17:04:50 -0700
Subject: [PATCH 1/2] docs: Document idkit-standalone migration
---
docs.json | 5 +-
world-id/from-idkit-standalone.mdx | 188 +++++++++++++++++++++++++++++
2 files changed, 192 insertions(+), 1 deletion(-)
create mode 100644 world-id/from-idkit-standalone.mdx
diff --git a/docs.json b/docs.json
index 712b3a5..eebbb89 100644
--- a/docs.json
+++ b/docs.json
@@ -93,7 +93,10 @@
},
{
"group": "Migration",
- "pages": ["world-id/4-0-migration"]
+ "pages": [
+ "world-id/4-0-migration",
+ "world-id/from-idkit-standalone"
+ ]
},
{
"group": "Technical Reference",
diff --git a/world-id/from-idkit-standalone.mdx b/world-id/from-idkit-standalone.mdx
new file mode 100644
index 0000000..c381152
--- /dev/null
+++ b/world-id/from-idkit-standalone.mdx
@@ -0,0 +1,188 @@
+---
+title: "IDKit Standalone"
+description: "Migrate from @worldcoin/idkit-standalone to @worldcoin/idkit-core."
+"og:image": "https://raw.githubusercontent.com/worldcoin/developer-docs/main/images/docs/docs-meta.png"
+"twitter:image": "https://raw.githubusercontent.com/worldcoin/developer-docs/main/images/docs/docs-meta.png"
+---
+
+{/* cspell:ignore idkit standalone rp_context app_id rp_id orblegacy signal_hash nullifier nullifiers verifyCloudProof pollUntilCompletion connectorURI */}
+
+This guide helps you migrate from `@worldcoin/idkit-standalone` to `@worldcoin/idkit-core`. The `idkit-standalone` package has been discontinued. If you used it
+for a vanilla JavaScript or custom QR flow, migrate to `@worldcoin/idkit-core`.
+ยก
+## Migration Checklist
+
+1. Enable World ID 4.0 in the [Developer Portal](https://developer.world.org) and keep your `app_id`, `rp_id`, and server-only `signing_key`.
+2. Install `@worldcoin/idkit-core`.
+3. Add a backend endpoint that generates an RP signature. See [RP Signatures](/world-id/idkit/signatures).
+4. Pick a legacy preset that matches your previous `verification_level` configuration.
+5. Replace `verifyCloudProof(...)` with a backend POST to `https://developer.world.org/api/v4/verify/{rp_id}`.
+6. Store the verified `nullifier` for replay protection.
+
+For the broader protocol migration, including proof types and timelines, see
+[World ID 4.0](/world-id/4-0-migration).
+
+## Install
+
+
+```bash npm
+npm i @worldcoin/idkit-core
+```
+
+```bash pnpm
+pnpm add @worldcoin/idkit-core
+```
+
+```bash yarn
+yarn add @worldcoin/idkit-core
+```
+
+
+## Request a Proof
+
+In standalone, the package mounted UI through browser globals:
+
+```ts title="Before"
+import "@worldcoin/idkit-standalone";
+
+IDKit.init({
+ app_id: "app_xxxxx",
+ action: "my-action",
+ signal: "user-123",
+ verification_level: "orb",
+});
+
+await IDKit.open();
+```
+
+With `idkit-core`, fetch an RP signature from your backend, build the request,
+render the `connectorURI`, and poll until World App returns a proof.
+
+```ts title="After"
+import { IDKit, orbLegacy } from "@worldcoin/idkit-core";
+
+const action = "my-action";
+const signal = "user-123";
+
+const rpSig = await fetch("/api/rp-signature", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ action }),
+}).then((r) => r.json());
+
+const request = await IDKit.request({
+ app_id: "app_xxxxx",
+ action,
+ rp_context: {
+ rp_id: "rp_xxxxx",
+ nonce: rpSig.nonce,
+ created_at: rpSig.created_at,
+ expires_at: rpSig.expires_at,
+ signature: rpSig.sig,
+ },
+ allow_legacy_proofs: true,
+ environment: "production",
+}).preset(orbLegacy({ signal }));
+
+renderQrCode(request.connectorURI);
+
+const completion = await request.pollUntilCompletion({
+ pollInterval: 2_000,
+ timeout: 120_000,
+});
+
+if (!completion.success) {
+ throw new Error(`World ID verification failed: ${completion.error}`);
+}
+
+await fetch("/api/verify-proof", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ idkitResponse: completion.result }),
+});
+```
+
+## Credential Mapping
+
+Standalone used `verification_level` to choose what the user should prove. In
+`idkit-core`, use a legacy preset instead. These presets are drop-in
+replacements for the old verification levels.
+
+
+ The legacy presets will return the maximum credential a user has. For example, if a user has an Orb credential, but you request `documentLegacy`, they will verify with their Orb credential.
+
+
+| Standalone | `idkit-core` preset |
+| --- | --- |
+| `verification_level: "orb"` | `orbLegacy({ signal })` |
+| `verification_level: "secure_document"` | `secureDocumentLegacy({ signal })` |
+| `verification_level: "document"` | `documentLegacy({ signal })` |
+| `verification_level: "device"` | `deviceLegacy({ signal })` |
+
+```ts
+import {
+ IDKit,
+ deviceLegacy,
+ documentLegacy,
+ orbLegacy,
+ secureDocumentLegacy,
+} from "@worldcoin/idkit-core";
+
+const request = await IDKit.request(config).preset(
+ orbLegacy({ signal: "user-123" }),
+);
+```
+
+
+## RP Signatures
+
+IDKit 4.x requests require `rp_context`, signed by your backend with the
+Developer Portal `signing_key`. Do not generate signatures in client code.
+
+For implementation details, use the [RP Signatures](/world-id/idkit/signatures)
+reference. It includes the JavaScript helper, the signing algorithm, and test
+vectors for non-JavaScript backends.
+
+## Verify the Proof
+
+Standalone integrations usually verified with `verifyCloudProof(...)`:
+
+```ts title="Before"
+import { verifyCloudProof } from "@worldcoin/idkit";
+
+const response = await verifyCloudProof(proof, app_id, action, signal);
+```
+
+In IDKit 4.x, send the IDKit result to your backend and forward it directly to
+the [v4 verify endpoint](/api-reference/developer-portal/verify).
+
+```ts title="After"
+import type { IDKitResult } from "@worldcoin/idkit-core";
+
+export async function POST(request: Request): Promise {
+ const { idkitResponse } = (await request.json()) as {
+ idkitResponse: IDKitResult;
+ };
+
+ const response = await fetch(
+ `https://developer.world.org/api/v4/verify/${process.env.WORLD_ID_RP_ID}`,
+ {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify(idkitResponse),
+ },
+ );
+
+ return new Response(await response.text(), {
+ status: response.status,
+ headers: { "content-type": "application/json" },
+ });
+}
+```
+
+## Store the Nullifier
+
+After `/api/v4/verify/{rp_id}` succeeds, store the verified `nullifier` for the
+action and reject duplicates. During migration, keep checking any old
+`nullifier_hash` records if the same user could have verified before the
+upgrade.
From 5c759443b1a787bc05107a602adefb96c9610310 Mon Sep 17 00:00:00 2001
From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com>
Date: Fri, 19 Jun 2026 17:31:12 -0700
Subject: [PATCH 2/2] rename
---
world-id/from-idkit-standalone.mdx | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/world-id/from-idkit-standalone.mdx b/world-id/from-idkit-standalone.mdx
index c381152..fc47f4b 100644
--- a/world-id/from-idkit-standalone.mdx
+++ b/world-id/from-idkit-standalone.mdx
@@ -64,7 +64,7 @@ import { IDKit, orbLegacy } from "@worldcoin/idkit-core";
const action = "my-action";
const signal = "user-123";
-const rpSig = await fetch("/api/rp-signature", {
+const rpContext = await fetch("/api/rp-signature", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ action }),
@@ -75,10 +75,10 @@ const request = await IDKit.request({
action,
rp_context: {
rp_id: "rp_xxxxx",
- nonce: rpSig.nonce,
- created_at: rpSig.created_at,
- expires_at: rpSig.expires_at,
- signature: rpSig.sig,
+ nonce: rpContext.nonce,
+ created_at: rpContext.created_at,
+ expires_at: rpContext.expires_at,
+ signature: rpContext.sig,
},
allow_legacy_proofs: true,
environment: "production",