> ## Documentation Index
> Fetch the complete documentation index at: https://docs.deepface.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript API examples

> Complete JavaScript verify, represent and compare examples with safe local inputs and no automatic compute retries.

# JavaScript API examples

Use Node.js 24 in your backend. Save the four files below together.
No private repository access, Python model installation, or extra client package is required.

## Before sending a request

Use only images and embeddings you are authorized to process. Configure
`DEEPFACE_API_KEY` through your secret manager or a server-side environment,
never in browser/mobile code, chat, a command argument, or a URL.
If no credential is configured, these examples stop before network access.
Follow [authentication](/authentication.md) for the existing owner-confirmed setup;
prepare code while the owner verifies their email. Use a standard REST key here,
not a dedicated MCP key.

Each command checks public capabilities and uses the current default model.
Set `DEEPFACE_MODEL` only for an allowed model with reviewed commercial rights.
`DEEPFACE_API_BASE_URL` defaults to `https://api.deepface.dev`; HTTPS is required
except HTTP loopback for local tests. Redirects are rejected.

## Run the examples

```bash theme={null}
node verify.mjs person-a.jpg person-b.jpg
node represent.mjs face.jpg
# Optional explicit local export of sensitive embeddings (new file only):
node represent.mjs face.jpg embeddings.json
node compare.mjs vectors.json
```

Use JPEG, PNG or WebP files. JavaScript sends multipart images; Python sends
base64 JSON. The comparison file contains `source_vector` and either
`target_vector` or `target_vectors`, with optional `distance_metric` and
`threshold`. Use embeddings from the same model and preprocessing pipeline;
matching dimensions alone are insufficient. Choose and evaluate a threshold
for your own permitted inputs rather than treating any nearest vector as identity.
The model is selected from capabilities (or `DEEPFACE_MODEL`), not inferred
from the vector file.

The embedding export contains the complete representation result. Protect it
as sensitive data, keep it out of version control, and delete it when no longer
needed. It is created with owner-only permissions and refuses overwrites.
The ordinary console summary contains no embeddings or submitted images.

## Outcomes and costs

Commands return a nonzero exit status for failed, no-face, pending, malformed or
unknown outcomes. A non-match is a completed verification, not a transport error.
Without a comparison threshold, the summary reports `match_evaluation: not_requested`
and omits the match count.
No-face detections can be billable even when returned as HTTP 422; inspect
[errors](/api-reference/errors.md) and [pricing](/pricing-governance.md). A saved
example or successful fixture is not an accuracy claim for your users.

These examples send at most one compute request per command. They do not retry
a 429, 503, timeout or lost response automatically. A transport/parse failure
reports `compute_outcome_unknown`, its request ID and `retryable: false`.
Computation may have completed; investigate before another attempt. Reusing a
request ID is not a result-retrieval or idempotency guarantee.
If a local export fails after a completed result, do not rerun inference
to repeat the export.

Default examples omit `X-Request-Priority`: positive priority can increase
completed-call pricing. Change priority or enable paid use only with the
owner's authority. Review [limits and retry semantics](/api-reference/rate-limits.md)
and [production outcomes, cost and retries](/guides/production-retries.md)
before adding production concurrency, retry or billing behavior.

## Files

### client.mjs

```javascript theme={null}
import { readFile, writeFile } from "node:fs/promises";
import { randomUUID } from "node:crypto";
import { extname } from "node:path";

class ExampleError extends Error {
  constructor(code, details = {}) { super(code); this.details = details; }
}

export function getConfig(env = process.env) {
  if (!env.DEEPFACE_API_KEY?.trim()) throw new ExampleError("missing_api_key");
  let url;
  try { url = new URL(env.DEEPFACE_API_BASE_URL || "https://api.deepface.dev"); }
  catch { throw new ExampleError("invalid_api_base"); }
  const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
  if ((url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) || url.username || url.password || url.search || url.hash) {
    throw new ExampleError("invalid_api_base");
  }
  return { base: url.href.replace(/\/$/, ""), key: env.DEEPFACE_API_KEY.trim(), model: env.DEEPFACE_MODEL };
}

export async function getModel(config) {
  try {
    const response = await fetch(`${config.base}/capabilities`, { redirect: "error", signal: AbortSignal.timeout(15_000) });
    if (!response.ok) throw new Error();
    const capabilities = await response.json();
    const model = config.model || capabilities.default_model;
    if (!capabilities.allowed_models?.includes(model)) throw new Error();
    return model;
  } catch { throw new ExampleError("capabilities_or_model_unavailable"); }
}

export async function image(path) {
  const type = { ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".webp": "image/webp" }[extname(path || "").toLowerCase()];
  if (!type) throw new ExampleError("provide_local_jpeg_png_or_webp");
  return new Blob([await readFile(path)], { type });
}

const finite = (value) => typeof value === "number" && Number.isFinite(value);
const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
const named = (value) => typeof value === "string" && value.trim().length > 0;

function validResult(endpoint, data) {
  if (endpoint === "/verify") return object(data) && typeof data.verified === "boolean" && finite(data.distance) && finite(data.threshold);
  if (endpoint === "/represent") return Array.isArray(data) && data.length > 0 && data.every((face) => object(face) && named(face.model_name) && Array.isArray(face.embedding) && face.embedding.length > 0 && face.embedding.every(finite));
  if (endpoint !== "/compare" || !object(data)) return false;
  const threshold = data.threshold;
  const result = (item) => object(item) && Number.isInteger(item.index) && item.index >= 0 && finite(item.distance) && (threshold == null ? item.match === undefined : typeof item.match === "boolean");
  return named(data.model_name) && ["cosine", "euclidean", "euclidean_l2"].includes(data.metric)
    && (threshold == null || finite(threshold)) && object(data.source)
    && ["image", "vector"].includes(data.source.type) && Number.isInteger(data.source.vector_length) && data.source.vector_length > 0
    && Array.isArray(data.results) && data.results.length > 0 && data.results.every(result)
    && (data.best_match === undefined || result(data.best_match));
}

export async function compute(endpoint, options, config, send = fetch) {
  const requestId = randomUUID();
  let response, data;
  try {
    response = await send(`${config.base}${endpoint}`, {
      ...options, method: "POST", redirect: "error", signal: AbortSignal.timeout(120_000),
      headers: { ...options.headers, Authorization: `Bearer ${config.key}`, "x-request-id": requestId },
    });
    data = await response.json();
  } catch { throw new ExampleError("compute_outcome_unknown", { request_id: requestId, retryable: false }); }
  const echoedId = response.headers.get("x-request-id");
  const id = /^[a-zA-Z0-9_-]{1,128}$/.test(echoedId || "") ? echoedId : requestId;
  if (response.status === 202) throw new ExampleError("compute_outcome_unknown", { request_id: id, retryable: false });
  if (!response.ok || data?.outcome === "no_face_detected") {
    const code = typeof data?.error === "string" && /^[a-z0-9_]{1,80}$/.test(data.error) ? data.error : data?.outcome === "no_face_detected" ? "no_face_detected" : `http_${response.status}`;
    throw new ExampleError(code, { status: response.status, request_id: id, retryable: false });
  }
  const valid = validResult(endpoint, data);
  if (!valid) throw new ExampleError("compute_outcome_unknown", { request_id: id, retryable: false });
  return { request_id: id, data };
}

export function summarize({ request_id, data }) {
  if (Array.isArray(data)) return { request_id, outcome: "completed", faces: data.length, dimensions: data.map((face) => face.embedding.length) };
  if (typeof data.verified === "boolean") return { request_id, outcome: "completed", verified: data.verified, distance: typeof data.distance === "number" && Number.isFinite(data.distance) ? data.distance : undefined, threshold: typeof data.threshold === "number" && Number.isFinite(data.threshold) ? data.threshold : undefined };
  const summary = { request_id, outcome: "completed", comparisons: data.results.length, match_evaluation: data.threshold == null ? "not_requested" : "threshold_applied" };
  if (data.threshold != null) Object.assign(summary, { threshold: data.threshold, matches: data.results.filter((result) => result.match === true).length });
  return summary;
}

export async function saveResult(path, data) {
  // Explicit local export only. Refuse to overwrite an existing file.
  await writeFile(path, JSON.stringify(data), { flag: "wx", mode: 0o600 });
}

export async function run(main) {
  try { await main(); }
  catch (error) {
    console.error(JSON.stringify({ error: error instanceof ExampleError ? error.message : "local_input_or_output_error", ...(error instanceof ExampleError ? error.details : {}) }));
    process.exitCode = 1;
  }
}
```

### verify.mjs

```javascript theme={null}
import { getConfig, getModel, image, compute, summarize, run } from "./client.mjs";

await run(async () => {
  const config = getConfig();
  const form = new FormData();
  form.set("img1", await image(process.argv[2]), "person-a.jpg");
  form.set("img2", await image(process.argv[3]), "person-b.jpg");
  form.set("model_name", await getModel(config));
  console.log(JSON.stringify(summarize(await compute("/verify", { body: form }, config))));
});
```

### represent.mjs

```javascript theme={null}
import { getConfig, getModel, image, compute, summarize, saveResult, run } from "./client.mjs";

await run(async () => {
  const config = getConfig();
  const form = new FormData();
  form.set("img", await image(process.argv[2]), "face.jpg");
  form.set("model_name", await getModel(config));
  const result = await compute("/represent", { body: form }, config);
  console.log(JSON.stringify(summarize(result)));
  if (process.argv[3]) await saveResult(process.argv[3], result.data);
});
```

### compare.mjs

```javascript theme={null}
import { readFile } from "node:fs/promises";
import { getConfig, getModel, compute, summarize, run } from "./client.mjs";

await run(async () => {
  const config = getConfig();
  const input = JSON.parse(await readFile(process.argv[2], "utf8"));
  // Copy only the documented vector-comparison inputs, never arbitrary headers.
  const { source_vector, target_vector, target_vectors, distance_metric, threshold } = input;
  const payload = { source_vector, target_vector, target_vectors, distance_metric, threshold, model_name: await getModel(config) };
  console.log(JSON.stringify(summarize(await compute("/compare", { headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }, config))));
});
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.