मुख्य सामग्री पर जाएं
गाइड

Node.js app में actor context कैसे जोड़ें

एक step-by-step guide जो middleware बनाता है और हर request के पीछे कौन या क्या है, इसे record करता है, ताकि आप किसी भी enforcement से पहले वास्तविक traffic का अध्ययन कर सकें.

Toshendra Sharma

द्वारा Toshendra Sharmaसंस्थापक और CEO, AgentCredia · Updated November 13, 2026

शुरुआती · 9 मिनट पढ़ें

Rules के बजाय actor context से शुरुआत क्यों करें?

ज्यादातर teams जो अपने traffic में AI agents को notice करती हैं, सबसे पहले rule लगाती हैं. user agent block करें, challenge जोड़ें, rate limit कड़ा करें. समस्या यह है कि traffic को समझने से पहले लिखा गया rule अक्सर गलत लोगों पर असर डालता है. legitimate assistants block हो जाते हैं, real users challenge का सामना करते हैं, और जिस automation की आपको वास्तव में चिंता थी, वह आती रहती है क्योंकि उसने शुरू से खुद को identify ही नहीं किया था.

Actor context rules से पहले का चरण है. हर request के लिए, आप यह record करते हैं कि आपका application किस चीज़ को observe कर सकता है जो act कर रही है: एक interactive person, AI assistant के साथ काम कर रहा person, एक autonomous agent, या कुछ ऐसा जिसे आप अभी अलग नहीं कर सकते. आप उस view के पीछे का evidence record करते हैं, और उसे request के outcome के साथ रखते हैं. एक या दो हफ्तों बाद, आपके पास वह होता है जो कोई rule template नहीं दे सकता: आपके अपने traffic का map. अगर आप अभी भी तय कर रहे हैं कि agents आपकी site तक पहुँचते भी हैं या नहीं, तो website traffic AI agents से आता है या नहीं, यह कैसे पता करें से शुरुआत करें.

यह guide plain middleware का उपयोग करके एक Node.js application में वह layer बनाती है. यह Express के साथ काम करती है, और वही विचार Fastify, Koa, Hono या Next.js route handler पर भी लागू होते हैं.

आप क्या बनाएंगे

अंत तक आपके पास होगा:

  1. एक middleware जो हर request से actor evidence निकालता है.
  2. एक छोटा, स्पष्ट classification, जिसके हर result के लिए stated basis होगा.
  3. Structured observation logs जो request को handle करने के तरीके को कभी नहीं बदलते.
  4. Result को request से जोड़ने का तरीका, ताकि बाद के handlers उसे पढ़ सकें.

यहाँ कुछ भी request को block नहीं करता. यह जानबूझकर है.

Step 1: आपका server वास्तव में कौन सा evidence देख सकता है?

Server उतना नहीं देखता जितना लोग मान लेते हैं. Code लिखने से पहले, अपनी edge पर उपलब्ध signals की सूची बनाएं:

  • Request signatures. कुछ automated clients HTTP Message Signatures (RFC 9421) का उपयोग करके requests sign करते हैं, Signature-Input और Signature headers भेजते हैं, अक्सर Signature-Agent header के साथ जो operator की प्रकाशित keys की ओर इशारा करता है, जैसा कि IETF Web Bot Auth protocol draft में वर्णित है.
  • Declared identity. Clients खुद को User-Agent header में, एक From header में, या protocol metadata के माध्यम से, जैसे MCP client name, नाम दे सकते हैं. MCP clients 2025-11-25 revision के initialize request में एक self-chosen clientInfo name report करते हैं, और 2026-07-28 revision client identity को per-request metadata के रूप में carry करती है. ये declarations हैं, और कोई भी इन्हें copy कर सकता है.
  • Authentication context. क्या request में session cookie, bearer token या API key है, और credential किस प्रकार का है.
  • Protocol shape. Accept headers, क्या client HTML या JSON request कर रहा है, क्या वह page assets load करता है, और redirects तथा cookies को कैसे handle करता है.
  • Application declarations. आपका अपना product ऐसी बातें जान सकता है जो network नहीं जानता, जैसे किसी user का "AI assisted" option चुनना, या आपकी built-in assistant feature से आने वाली request.

हर signal की strength अलग होती है. A validated signature check की जा सकती है. A user agent string एक claim है. Missing cookie बस missing है. इन सबको अलग रखना ही इस exercise का असली उद्देश्य है.

Step 2: Result को स्पष्ट रूप से model करें

Detection logic लिखने से पहले actor result का shape define करें. एक छोटा, typed model सभी को इस बारे में ईमानदार रखता है कि classification का मतलब क्या है. यहाँ उपयोग की गई चार classes Human, AI-assisted or agent: application traffic के लिए एक practical taxonomy में समझाई गई हैं.

TS
export type ActorClass = "human" | "human_ai" | "agent" | "unknown";
export type EvidenceBasis = "verified" | "declared" | "inferred" | "unknown";

export interface ActorEvidence {
  signaturePresent: boolean;
  signatureAgent?: string;
  declaredClient?: string;
  credentialType: "session" | "api_key" | "bearer" | "none";
  acceptsHtml: boolean;
  appDeclaredAssist: boolean;
}

export interface ActorResult {
  actor: ActorClass;
  basis: EvidenceBasis;
  reasons: string[];
  evidence: ActorEvidence;
  observedAt: string;
}

दो fields सबसे ज़्यादा महत्वपूर्ण हैं. actor class है. basis बताता है कि आप ऐसा क्यों मानते हैं. Validated signature पर आधारित agent result और user agent string पर आधारित agent result दोनों "agent" हैं, लेकिन बाद में उन्हें बहुत अलग treatment की ज़रूरत होती है, इसलिए आप उन्हें कभी merge नहीं करते.

Step 3: Middleware में evidence निकालें

Extraction step headers और request state पढ़ता है. यह अभी किसी भी बात का निर्णय नहीं करता.

TS
import type { Request, Response, NextFunction } from "express";

const KNOWN_AGENT_TOKENS = ["bot", "crawler", "spider", "agent", "gpt", "claude"];

export function extractEvidence(req: Request): ActorEvidence {
  const ua = (req.get("user-agent") || "").toLowerCase();
  const auth = req.get("authorization") || "";
  const hasSession = Boolean(req.cookies?.session);

  let credentialType: ActorEvidence["credentialType"] = "none";
  if (hasSession) credentialType = "session";
  else if (auth.toLowerCase().startsWith("bearer ")) credentialType = "bearer";
  else if (req.get("x-api-key")) credentialType = "api_key";

  const declaredToken = KNOWN_AGENT_TOKENS.find((t) => ua.includes(t));

  return {
    signaturePresent: Boolean(req.get("signature") && req.get("signature-input")),
    signatureAgent: req.get("signature-agent") || undefined,
    declaredClient: declaredToken ? ua.slice(0, 200) : undefined,
    credentialType,
    acceptsHtml: (req.get("accept") || "").includes("text/html"),
    appDeclaredAssist: req.get("x-app-assist") === "1",
  };
}

इस code पर कुछ notes:

  • signaturePresent सिर्फ यह record करता है कि signature headers मौजूद हैं. Validation एक अलग step है, जिसे signed agent requests को verify करने वाले guide में cover किया गया है.
  • user agent token list जानबूझकर simple रखी गई है. यह एक declaration बनाती है, कभी verification नहीं.
  • x-app-assist आपकी own frontend जो भेजती है उसके लिए placeholder है, जब कोई user आपकी built-in AI feature के माध्यम से काम करता है. इसे अपने real mechanism से replace करें.

Step 4: Stated basis के साथ classify करें

अब evidence को result में बदलें. Rules छोटे रखें, strongest evidence से weakest तक ordered रखें, और हमेशा Unknown पर fall through करें.

TS
export async function classify(
  evidence: ActorEvidence,
  verifySignature: () => Promise<boolean>,
): Promise<ActorResult> {
  const reasons: string[] = [];
  const observedAt = new Date().toISOString();

  if (evidence.signaturePresent && (await verifySignature())) {
    reasons.push("request signature validated");
    return { actor: "agent", basis: "verified", reasons, evidence, observedAt };
  }

  if (evidence.appDeclaredAssist) {
    reasons.push("application reported its built-in assistant");
    return { actor: "human_ai", basis: "declared", reasons, evidence, observedAt };
  }

  if (evidence.declaredClient) {
    reasons.push("client declared itself as automated");
    return { actor: "agent", basis: "declared", reasons, evidence, observedAt };
  }

  if (evidence.credentialType === "session" && evidence.acceptsHtml) {
    reasons.push("interactive browser session");
    return { actor: "human", basis: "inferred", reasons, evidence, observedAt };
  }

  reasons.push("insufficient evidence");
  return { actor: "unknown", basis: "unknown", reasons, evidence, observedAt };
}

ध्यान दें कि यह क्या नहीं करता. यह कभी declaration को verification में नहीं बदलता. यह कभी ऐसी request को Human नहीं देता जिसमें interactive signal नहीं है. जब यह तय नहीं कर पाता, तो यह Unknown कहता है. Unknown एक valid, उपयोगी answer है, और यह आपको ठीक-ठीक बताता है कि आपकी visibility कहाँ समाप्त होती है. हम पूरा पक्ष AI traffic के लिए Unknown एक valid result क्यों है में प्रस्तुत करते हैं.

Step 5: Observation mode में इसे wire करें

Middleware को early mount करें, result को request से attach करें, और log करें. उस पर branch न करें.

TS
import express from "express";
import cookieParser from "cookie-parser";

const app = express();
app.use(cookieParser());

app.use(async (req, res, next) => {
  try {
    const evidence = extractEvidence(req);
    const result = await classify(evidence, async () => false);
    res.locals.actor = result;

    res.on("finish", () => {
      logActor({
        route: req.route?.path ?? req.path,
        method: req.method,
        status: res.statusCode,
        actor: result.actor,
        basis: result.basis,
        reasons: result.reasons,
      });
    });
  } catch {
    res.locals.actor = undefined;
  }
  next();
});

तीन बातें इसे safe बनाती हैं:

  1. try block यह सुनिश्चित करता है कि detection में failure कभी response को प्रभावित न करे. Observation को fail open होना चाहिए.
  2. Logging finish पर होती है, इसलिए आप वास्तविक status code capture करते हैं और बाद में classifications को outcomes से compare कर सकते हैं.
  3. जब तक आप real validation implement नहीं करते, verifySignature को false पर stub किया गया है. इससे signed requests declared या unknown buckets में रहती हैं, बजाय इसके कि उन्हें बढ़ा-चढ़ाकर बताया जाए.

Step 6: Analysis के लिए log करें, सिर्फ debugging के लिए नहीं

ऐसे logs लिखें जिन्हें आप aggregate कर सकें. प्रति request एक structured line पर्याप्त है.

TS
function logActor(entry: Record<string, unknown>) {
  process.stdout.write(JSON.stringify({ type: "actor_observation", ...entry }) + "\n");
}

इन logs से personal data दूर रखें. आपको route, class, basis, reasons और outcome चाहिए. अपने traffic mix को समझने के लिए full IP addresses, raw cookies या request bodies की आवश्यकता नहीं है. अगर correlation के लिए कोई identifier रखते हैं, तो उसे rotating salt के साथ hash करें और retention period छोटा रखें.

Step 7: Action लेने से पहले data पढ़ें

Observation mode में इतना समय चलाएं कि सामान्य weekly patterns दिखाई दें. फिर कुछ सवालों के जवाब दें:

  • कौन से routes agents को आकर्षित करते हैं? Documentation, catalog और search endpoints अक्सर करते हैं. Account और checkout flows आमतौर पर नहीं करने चाहिए.
  • Agent results का कितना हिस्सा verified बनाम declared है? यह ratio बताता है कि policy लिखते समय identity पर आप कितनी सुरक्षित रूप से निर्भर कर सकते हैं.
  • Unknown कहाँ concentrated है? किसी route पर high Unknown rate अक्सर मतलब होता है कि वहाँ कोई signal missing है, उदाहरण के लिए ऐसा page जो कभी आपका frontend code चलाता ही नहीं.
  • क्या outcomes class के अनुसार अलग हैं? Error rates, conversion steps या abuse reports को classes के बीच compare करें. यहीं से वास्तविक policy ideas आते हैं.

जवाब अक्सर चौंकाते हैं. Teams नियमित रूप से पाती हैं कि उनकी "bot problem" का बड़ा हिस्सा वास्तव में legitimate automation है, जो अगर structured endpoint होता तो खुशी से उसका उपयोग करती.

Step 8: Result को अपनी app के बाकी हिस्से के लिए expose करें

एक बार data flow होने लगे, तो handlers को res.locals.actor non-enforcing uses के लिए पढ़ने दें: analytics tags, response format चुनना, या यह record करना कि support ticket AI-assisted session से आया था. ये उपयोग अनुभव को बेहतर बनाते हैं, बिना किसी को lock out किए.

TS
app.get("/docs/:page", (req, res) => {
  const actor = res.locals.actor as ActorResult | undefined;
  if (actor?.actor === "agent" && req.accepts("text/markdown")) {
    return res.type("text/markdown").send(renderMarkdown(req.params.page));
  }
  return res.render("doc", { page: req.params.page });
});

Enforcement, जैसे challenges, rate limits या step-up checks, बाद में आता है, false positives को माप लेने के बाद. actor-aware policies को roll out करने वाला guide उस process को cover करता है.

आपको किन गलतियों से बचना चाहिए?

  • User agent को identity मानना. इसे बदलना सबसे आसान header है. इसे declaration के रूप में record करें. AI operators भी यही कहते हैं: Anthropic's guidance for its hosted browser agent नोट करती है कि कोई भी वही User-Agent header भेज सकता है और traffic को genuine मानने से पहले published IP addresses जांचने की सलाह देती है.
  • Human को default बनाना. अगर आपका code bot signals न मिलने पर Human कहता है, तो आपके Human numbers inflated होंगे और आपकी policies गलत traffic पर भरोसा करेंगी.
  • Class और basis को मिलाना. हमेशा दोनों store करें. केवल "Agent" दिखाने वाला dashboard verified operator और copied string के बीच का फर्क छिपा देता है.
  • Observation के दौरान block करना. Temporary block भी आपकी measurements को invalid कर देता है, क्योंकि blocked clients अपना व्यवहार बदल देते हैं.

Proof of Actor कहाँ fit होता है

ऊपर दिया गया middleware एक मजबूत starting point है, और यह core model दिखाता है: पहले evidence, हर result के लिए स्पष्ट basis, Unknown को visible रखना, और decisions को आपकी application पर छोड़ देना. Proof of Actor उसी model पर server, edge, browser और MCP contexts में deeper signal coverage तथा analytics के साथ आगे बढ़ता है, जिससे आप Detect, Understand और Route confidence के साथ कर सकें.

अगर आप इसे production app पर आगे ले जाने में मदद चाहते हैं, तो early access के लिए apply करें. पूरे decision flow को देखने के लिए, Proof of Actor कैसे काम करता है पढ़ें.

Sources

इसे हमारे साथ बनाएं।

Proof of Actor founding developer program में शामिल हों।

क्या पहले बात करना पसंद करेंगे? founders से बात करें