@localtools/ai-meta is a native Node.js addon (N-API via node-addon-api, not NAN or raw V8) for detecting, extracting, stripping, and writing AI-generation metadata declared in image files.
It wraps the ai_meta C library and links prebuilt release binaries of that library (pinned by LIBAI_META_VERSION).
- Repository: https://github.com/localtools/ai-meta-node
- License: MIT — free and open source
- Node.js: 18+ (N-API version 8)
- Scope: declared metadata only — it does not analyze pixels to guess whether an undeclared image is AI-generated
Sibling projects: ai-meta (C), ai-meta-php.
Generators and platforms increasingly embed provenance and generation parameters (Stable Diffusion parameters, EXIF/XMP, C2PA Content Credentials, IPTC). This package gives Node.js applications a small, dependency-light way to inspect and scrub that metadata while leaving pixel data and color profiles intact when requested.
| Capability | Notes |
|---|---|
| Formats | PNG, JPEG, WebP |
| Schemes | PNG text (tEXt / iTXt / zTXt), EXIF, XMP, IPTC (JPEG), C2PA detect/strip/hints |
| Sync API | scan / extract / strip / write for small buffers |
| Async API | *Async Promise variants via Napi::AsyncWorker (preferred for large images) |
| Flags | AiMetaFlags.STRIP_ALL_AI, KEEP_COLOR_PROFILE, … |
| Errors | AiMetaError with messages from ai_meta_strerror() |
C2PA signatures are not cryptographically verified (same as the C library).
- Node.js 18+
- A C++17 toolchain (
python3+node-gypbuild deps) - zlib development headers (
zlib1g-devon Debian/Ubuntu; usually present on macOS) - A prebuilt ai_meta prefix (
include/+lib/) — fetched automatically on install when missing
git clone https://github.com/localtools/ai-meta-node.git
cd ai-meta-node
npm install # ensure-libai-meta + node-gyp-build
npm testnpm install runs scripts/ensure-libai-meta.js (downloads LIBAI_META_VERSION into deps/ai_meta when needed) then node-gyp-build. The addon statically links lib/libai_meta.a, so only zlib is required at runtime.
Alternative discovery:
npm run fetch-lib
# Or point at an unpacked release / make install prefix:
export AI_META_PREFIX=/path/to/ai_meta-0.1.0-linux-x86_64
npm run rebuildSee examples/basic.js.
Once published:
npm install @localtools/ai-metaConsumers with a matching prebuild under prebuilds/ skip compilation; otherwise node-gyp builds the addon and still needs zlib + network (or a local AI_META_PREFIX) to obtain libai_meta.
GitHub Releases attach prebuildify binaries (platform/arch folders under prebuilds/):
npm run prebuild # local: writes under prebuilds/Tag a release to build assets, attach them to the GitHub Release, and publish @localtools/ai-meta to npm:
git tag v0.1.0
git push origin v0.1.0Requires repository secret NPM_TOKEN (npm automation/granular token with publish rights for @localtools). The workflow merges platform prebuilds/ into the package before npm publish --access public --provenance.
Human-friendly tarball of the built .node + docs:
./scripts/package-dist.sh| Item | Location |
|---|---|
| Releases | https://github.com/localtools/ai-meta/releases |
| Pin file | LIBAI_META_VERSION |
| Fetch helper | scripts/fetch-libai-meta.sh |
This package does not vendor or compile libai_meta sources.
scan(data: Buffer): { format: string; schemes: string[]; likelyAi: boolean }
extract(data: Buffer): Record<string, string>
strip(data: Buffer, flags?: number): Buffer
write(data: Buffer, key: string, value: string): Buffer
scanAsync(data: Buffer): Promise<…>
extractAsync(data: Buffer): Promise<…>
stripAsync(data: Buffer, flags?: number): Promise<Buffer>
writeAsync(data: Buffer, key: string, value: string): Promise<Buffer>
version(): stringconst {
scan,
extract,
strip,
write,
scanAsync,
AiMetaFlags,
AiMetaError,
} = require('@localtools/ai-meta');
const fs = require('fs');
const bytes = fs.readFileSync('in.png');
const info = scan(bytes);
if (info.likelyAi) {
const fields = extract(bytes);
// fields.parameters, fields.prompt, …
const clean = strip(
bytes,
AiMetaFlags.STRIP_ALL_AI | AiMetaFlags.KEEP_COLOR_PROFILE
);
fs.writeFileSync('out.png', clean);
}
const stamped = write(bytes, 'parameters', 'Steps: 20, Seed: 1');
// Prefer async for larger images (avoids blocking the event loop):
const asyncInfo = await scanAsync(bytes);On any non-OK library status, an AiMetaError (extends Error) is thrown.
TypeScript definitions: index.d.ts.
| Flag | Role |
|---|---|
NONE |
No strip flags |
STRIP_PNG_TEXT / STRIP_EXIF / STRIP_XMP / STRIP_IPTC / STRIP_C2PA |
Per-scheme strip |
STRIP_ALL_AI |
All AI-related strip bits |
KEEP_COLOR_PROFILE |
Preserve ICC / color profile when possible |
KEEP_NON_AI_TEXT |
Keep benign PNG text when stripping |
| Topic | Rule |
|---|---|
| Errors | Throw AiMetaError; message from ai_meta_strerror() |
| Memory | Library buffers are freed inside the addon before return |
| Strip / write | Always return a new Buffer |
| Color profiles | Preserved when KEEP_COLOR_PROFILE is set (recommended) |
| Event loop | Use *Async for large images |
- Thin N-API wrapper over the buffer-based C API
- Compiled dependency — links release artifacts of ai_meta, not a source copy
- Runtime deps — zlib (and Node); static
libai_meta.ais preferred at link time - Portability — Linux and macOS; CI covers Node.js 18 / 20 / 22
- Safety — malformed / truncated metadata should fail with an exception, not crash the process
- Pixel / ML-based “is this AI?” detection
- Full C2PA claim verification and signing
- Lossy re-encode of image payloads (metadata containers only)
- Bundling or re-implementing the C library inside this repo
npm testCoverage includes scan, extract, write/strip round-trip, async API, and error paths against small PNG fixtures under test/fixtures/.
package.json npm metadata + install hooks
binding.gyp node-gyp (links prebuilt libai_meta)
src/addon.cpp N-API implementation
index.js / index.d.ts JS entry + TypeScript types
examples/basic.js Minimal consumer
scripts/fetch-libai-meta.sh
scripts/ensure-libai-meta.js
scripts/package-dist.sh
test/*.test.js node:test suite
LIBAI_META_VERSION Pinned ai_meta release
LICENSE NOTICE MIT + third-party notices
Contributions are welcome. See CONTRIBUTING.md and our Code of Conduct.
For security issues, see SECURITY.md — please do not open public issues for vulnerabilities.
See CHANGELOG.md.
This project is licensed under the MIT License — see LICENSE and NOTICE.
Copyright (c) 2026 Local Tools and ai-meta-node contributors
You may use, modify, and distribute this software under the terms of that license.
The native ai_meta library is also MIT-licensed; prebuilt binaries are obtained from its GitHub Releases.