Choose an API
First choose the package for the environment that owns the work:
| Need | Package |
|---|---|
| Render in iOS, Android, or a browser | react-native-image-marker Core 2.1 |
| Render in a standalone browser, Vite app, or WebView without React Native | @image-marker/web 0.1 |
| Build a visual React Native or Web editing workspace | react-native-image-marker-editor |
| Create, validate, or migrate Recipe JSON without rendering | @image-marker/recipe |
| Render in a Node.js service | @image-marker/node |
| Render or inspect from a terminal or CI job | @image-marker/cli |
The three public methods share the same output options. Choose by layer type:
| Method | Use it for | Layer order |
|---|---|---|
Marker.markText |
One or many text watermarks | Text array order |
Marker.markImage |
One or many image watermarks | Image array order |
Marker.mark |
Text and image watermarks together | Exact watermarks array order |
Marker.createRecipe |
Reuse ordered layers across one or many images | Exact Recipe layers array order |
markText and markImage remain supported. Use mark when a single render needs both text and image layers or when cross-type ordering matters.
For a browser-only application, prefer @image-marker/web. It exposes the same
Web rendering contract without React Native peer dependencies and also provides
/headless, /editor-adapter, and the packaged invisible-watermark Worker.
import Marker, { ImageFormat, Position } from 'react-native-image-marker';
const result = await Marker.markText({ backgroundImage: { src: require('./background.jpg') }, watermarkTexts: [ { text: 'PRIVATE', position: { position: Position.center }, style: { color: '#FFFFFF99', fontSize: 42, bold: true, rotate: -18, }, }, ], saveFormat: ImageFormat.png,});import Marker, { ImageFormat, Position } from 'react-native-image-marker';
const result = await Marker.markImage({ backgroundImage: { src: require('./background.jpg') }, watermarkImages: [ { src: require('./logo.png'), position: { position: Position.topRight, X: 20, Y: 20, }, scale: 0.5, alpha: 0.9, }, ], saveFormat: ImageFormat.png,});import Marker, { ImageFormat, Position } from 'react-native-image-marker';
const result = await Marker.mark({ backgroundImage: { src: require('./background.jpg') }, watermarks: [ { type: 'image', src: require('./logo.png'), position: { position: Position.topRight, X: 20, Y: 20 }, scale: 0.5, }, { type: 'text', text: 'Acme Studio', position: { position: Position.bottomCenter, Y: 24 }, style: { color: '#FFFFFF', fontSize: 28 }, }, ], saveFormat: ImageFormat.png,});When to create a Recipe
Section titled “When to create a Recipe”Use createRecipe when the watermark structure stays the same while the background or displayed values change. Recipe v2 accepts the modern ordered layers array and nested output; pass backgroundImage, filename, and optional variables to apply() or applyMany() for each input. Text templates can read {{variableName}}, {{index}}, and {{filename}}; visibleWhen conditionally includes a layer.
applyMany() reports every item independently and preserves input order. Its default concurrency is 1. Web accepts up to 4 active jobs; iOS and Android stay at 1 to limit native memory pressure. An AbortSignal stops queued work and cancels the active native job when supported.
Set schemaVersion: 2 when a Recipe will be serialized, preserve stable layer id values, and persist recipe.toJSON() rather than internal runtime state. Use migrateWatermarkRecipe() once when importing a saved v1 document.
Layer order
Section titled “Layer order”Layers render in array order. A later layer is drawn over an earlier one. This is especially important with Marker.mark, where text and image layers share the same array.
Removed v1 properties
Section titled “Removed v1 properties”Core 2 requires the plural arrays and current position property:
| Avoid in new code | Use instead |
|---|---|
positionOptions on text |
position |
watermarkImage |
watermarkImages |
watermarkPositions |
position on each image layer |
| Separate calls for mixed content | One Marker.mark call |