Node.js SDK
The Node.js SDK is the recommended integration path for Node.js and TypeScript applications. It handles authentication, uploads, polling, result parsing, and streaming.
Installation
The SDK requires Node.js 20.9 or newer.
npm install @ice9/sdk
Image censoring is optional. Install Sharp only if your application calls
image.moderation.censor():
npm install sharp
Authentication
Pass your API key directly or use ICE9_API_KEY:
export ICE9_API_KEY=ice9_...
import { Ice9 } from "@ice9/sdk";
const client = new Ice9({ apiKey: process.env.ICE9_API_KEY });
Quickstart
import { Ice9 } from "@ice9/sdk";
const client = new Ice9({ apiKey: process.env.ICE9_API_KEY });
const image = await client.analyze("photo.jpg");
console.log(image.isNsfw);
console.log(image.category);
console.log(image.scene?.type);
console.log(image.moderation.reason);
Input types
analyze() accepts:
- local file paths
- image URLs
BufferUint8Array
const resultA = await client.analyze("photo.jpg");
const resultB = await client.analyze("https://example.com/photo.jpg");
const resultC = await client.analyze(buffer);
JPEG, PNG, WebP, HEIC, and HEIF buffers are identified from their file
signatures. For in-memory uploads you may also supply mediaType and
filename; the SDK validates the media type and normalizes the filename
extension to match the detected image:
const image = await client.analyze(buffer, {
mediaType: "image/webp",
filename: "upload.webp",
});
Unsupported or unidentifiable bytes fail locally with ImageRejectedError.
Image URLs are downloaded by the SDK, validated, limited to 10 MB, and then
uploaded to Ice9.
Tiers and service discovery
If you omit tier, the SDK uses the baseline basic tier.
const image = await client.analyze("photo.jpg");
const upgraded = await client.analyze("photo.jpg", { tier: "basic" });
const tiers = await client.tiers();
const services = await client.services();
See API Reference for the raw tier definitions.
Result model
The SDK exposes image-level helpers first and keeps raw service outputs available under image.services.
Core helpers
image.isNsfwimage.isSafeimage.categoryimage.captionimage.sceneimage.moderationimage.nounsimage.verbsimage.services
Scene summary
image.scene is derived from content_analysis and provides a product-shaped summary:
image.scene?.typeimage.scene?.intimacyimage.scene?.activityimage.scene?.activitiesimage.scene?.anatomyExposedimage.scene?.peopleimage.scene?.gender
Moderation helpers
const image = await client.analyze("photo.jpg");
if (image.isNsfw) {
console.log(image.moderation.reason);
await image.moderation.censor("photo.jpg", { output: "photo-censored.jpg" });
}
The default censoring policy covers exposed genitalia, breasts, buttocks, and
anus detections at confidence 0.5 or higher. Pass labels or minConfidence
to define your own policy. Censoring supports fill and pixelate, returns a
Buffer, and writes JPEG, PNG, or WebP according to format, the output
filename, or the input format where possible.
Sharp is not loaded for analysis or result parsing. Applications that do not use censoring do not need to install it.
Raw service access
Use image.services when you need service-level payloads:
console.log(image.services.nudenet);
console.log(image.services.colors);
console.log(image.services.metadata);
Streaming
Use stream: true to receive partial AnalysisResult objects as services complete:
import { Ice9 } from "@ice9/sdk";
const client = new Ice9({ apiKey: process.env.ICE9_API_KEY });
for await (const partial of client.analyze("photo.jpg", { tier: "basic", stream: true })) {
if (partial.isComplete) {
console.log("final caption:", partial.caption);
} else {
console.log("services seen:", partial.servicesSubmitted);
}
}
Retrieving results later
Use the retrieval helpers if you already have an imageId:
const status = await client.getStatus(1234);
const result = await client.getResult(1234);
getStatus() returns the raw /status payload. getResult() returns a parsed AnalysisResult.
Timeouts, retries, and partial results
The default analysis timeout is 95 seconds. Set timeout in seconds on the
client or for an individual analysis. Network failures and server errors are
retried up to three times by default; configure this with maxRetries.
By default, an analysis with failed services raises PartialResultError. The
exception includes the partial result. Set raiseOnPartial: false to return it
normally instead:
const image = await client.analyze("photo.jpg", {
timeout: 95,
raiseOnPartial: false,
});
Serialization
Use toJSON() or toJson() to serialize results:
const payload = image.toJSON();
const pretty = image.toJson(2);
Examples
Basic analysis
import { Ice9 } from "@ice9/sdk";
const client = new Ice9({ apiKey: process.env.ICE9_API_KEY });
const image = await client.analyze("photo.jpg", { tier: "basic" });
console.log(image.caption);
console.log(image.category);
console.log(image.scene?.type, image.scene?.intimacy);
for (const noun of image.nouns?.validated ?? []) {
console.log(noun);
}
Streaming
import { Ice9 } from "@ice9/sdk";
const client = new Ice9({ apiKey: process.env.ICE9_API_KEY });
for await (const partial of client.analyze("photo.jpg", { tier: "basic", stream: true })) {
console.log(partial.isComplete ? partial.caption : partial.servicesSubmitted);
}
Full runnable examples
For complete scripts and local downloads:
- https://github.com/ice9innovations/ice9-sdk/tree/main/nodejs/examples