Overview
Custom overlays let an application draw its own images on top of the live camera. Unlike a packaged .nosmai effect, a custom overlay uses an image that the application already has, such as a bundled asset, a downloaded file, a picture selected from the gallery, or an image at a network URL.
A custom overlay can be:
- a still PNG image
- an animated image played from a frame sequence or a GIF
- placed at a fixed screen position that the user can move, scale, and rotate
- attached to a face point such as the nose, lips, eyes, or head so it follows the face
Because a custom overlay is composited inside the Nosmai pipeline, it appears everywhere the processed frame is used:
- the live preview
- captured photos
- recorded video
- live streaming output
[!NOTE] Drawing an image in the application's own view layer only shows it on screen. A custom overlay is part of the processed frame, so it is also present in photos, recordings, and streams.
Custom overlays or a .nosmai effect
Custom overlays and packaged .nosmai effects solve different problems. Use the one that matches the content.
| Requirement | Recommended choice |
|---|---|
| The user places their own PNG, drawing, or gallery image | Custom overlay |
| A logo, badge, or branded watermark on the output | Custom overlay |
| An image chosen or moved at runtime | Custom overlay |
| Several movable stickers at once | Custom overlay |
| A downloadable, protected, or monetized effect | .nosmai effect |
| An authored face mask, 3D model, or particle experience | .nosmai effect |
| A coordinated makeup or beauty look | Built-in beauty or beauty_effect |
Custom overlays are an independent layer. They remain visible together with color filters, built-in beauty, backgrounds, and .nosmai effects. See Filters and effects for package slots and Beauty and makeup for built-in beauty.
Where you can use custom overlays
Custom overlays work in any camera experience built on Nosmai, because they are part of the processed frame. The same overlay reaches the preview, captured photos, recorded video, and live streams.
Common use cases include:
| Use case | What a custom overlay adds |
|---|---|
| Live streaming | A streamer badge, event banner, donation sticker, or brand watermark visible to every viewer |
| Video calls and conferencing | A name tag, team logo, or event label on the sent video |
| Short-video and social apps | Movable stickers the user places, scales, and rotates on a clip |
| Selfie and photo-booth apps | Fun face stickers on the nose, lips, eyes, or head |
| Branding and watermarks | A logo or campaign mark included in recorded and streamed output |
| Events and weddings | A custom frame, hashtag, or date overlay for shared media |
| Marketing and seasonal campaigns | A network-loaded promo sticker that can change without an app release |
| Live shopping and creators | A price tag, offer badge, or handle shown during a stream |
Live streaming
Because a custom overlay is composited before the frame leaves the SDK, it is included in the live-stream output, not only the local preview. A streamer badge, sponsor logo, or event banner is visible to every viewer through the same processed frame that carries filters, beauty, and effects.
This works with both native and Flutter streaming. Add the overlay after the preview is ready and keep it active for the whole session. See Native live streaming and Flutter live streaming with Agora.
Photo capture and recording
The same overlay is present in a captured photo and in recorded video, so a sticker, frame, or watermark carries into saved and shared media without a separate compositing step. Add the overlay before capture or before recording starts.
Before you start
Complete these steps first:
- Initialize the SDK with a valid license key.
- Show the Nosmai camera preview.
- Wait until the preview is ready.
- Add the overlay.
Face-attached overlays become visible when a face is detected. If the face leaves the camera view, the SDK hides the attached overlay and restores it when the face returns. A screen-anchored overlay does not require a face.
Image sources
An overlay image can come from several sources.
| Source | Use it for |
|---|---|
| Bundled asset | An image shipped inside the application |
| Local file | A downloaded or user-saved file on the device |
| Image bytes | An image the application already holds in memory |
| Network URL | An image hosted on a server |
| Frame sequence or GIF | An animated overlay |
Keep overlay images at a reasonable resolution. A very large image uses more memory and can lower the preview frame rate without improving the visible result.
Placement and anchors
An overlay is positioned with an anchor and a transform.
Anchor
The anchor decides where the overlay is placed.
| Anchor | Placement |
|---|---|
screen | A fixed position on the screen |
head | The top of the head |
nose | The nose |
lips | The lips |
eyes | Between the eyes |
leftEye | The left eye |
rightEye | The right eye |
Use screen for a movable sticker or a watermark. Use a face anchor for an overlay that should follow the face, such as glasses on the eyes or a shape on the nose.
Transform
Every overlay accepts the same transform values.
| Value | Meaning |
|---|---|
x, y | Position |
z | Depth and draw order |
scale | Size multiplier |
rotation | Rotation in degrees |
opacity | Transparency from 0.0 to 1.0 |
The transform is interpreted relative to the anchor:
- For the
screenanchor,xandyare normalized screen coordinates from0.0to1.0with the origin at the top-left, andzsets the draw order of overlapping overlays. - For a face anchor,
x,y, andzare offsets from the anchor point. The overlay is automatically scaled to the size of the detected face, andscalemultiplies that automatic size.
This means an application can select a face point and still fine-tune the exact placement:
finalPosition = anchorPoint + (x, y, z) finalSize = autoFaceSize × scale finalRotation = rotation
Add an overlay
Give each overlay a unique identifier so it can be updated or removed later.
Flutter
Add a screen-anchored sticker:
final nosmai = NosmaiFlutter.instance;
await nosmai.addOverlay(
id: 'heart',
source: NosmaiOverlaySource.asset('assets/stickers/heart.png'),
anchor: NosmaiOverlayAnchor.screen,
x: 0.5,
y: 0.5,
scale: 1.0,
rotation: 0.0,
opacity: 1.0,
);
Attach an overlay to a face point:
await nosmai.addOverlay(
id: 'glasses',
source: NosmaiOverlaySource.asset('assets/stickers/glasses.png'),
anchor: NosmaiOverlayAnchor.eyes,
x: 0.0,
y: -0.02,
z: 0.0,
scale: 1.0,
);
Available Flutter anchors:
NosmaiOverlayAnchor.screen NosmaiOverlayAnchor.head NosmaiOverlayAnchor.nose NosmaiOverlayAnchor.lips NosmaiOverlayAnchor.eyes NosmaiOverlayAnchor.leftEye NosmaiOverlayAnchor.rightEye
Available Flutter image sources:
NosmaiOverlaySource.asset('assets/stickers/star.png');
NosmaiOverlaySource.file('/path/to/sticker.png');
NosmaiOverlaySource.bytes(imageBytes);
NosmaiOverlaySource.network('https://cdn.example.com/star.png');
NosmaiOverlaySource.sequence(framePaths); // animated frames
iOS
NosmaiEffectsEngine *effects = [NosmaiCore shared].effects; NosmaiOverlayConfig *config = [[NosmaiOverlayConfig alloc] init]; config.identifier = @"heart"; config.anchor = NosmaiOverlayAnchorScreen; config.x = 0.5f; config.y = 0.5f; config.scale = 1.0f; config.rotation = 0.0f; config.opacity = 1.0f; UIImage *image = [UIImage imageNamed:@"heart"]; [effects addOverlay:config image:image];
Attach an overlay to a face point:
NosmaiOverlayConfig *config = [[NosmaiOverlayConfig alloc] init]; config.identifier = @"glasses"; config.anchor = NosmaiOverlayAnchorEyes; config.x = 0.0f; config.y = -0.02f; config.z = 0.0f; config.scale = 1.0f; [effects addOverlay:config image:[UIImage imageNamed:@"glasses"]];
Add from a file path or a network URL:
[effects addOverlayFromPath:localPath config:config]; [effects addOverlayFromURL:remoteURL config:config];
Available iOS anchors:
NosmaiOverlayAnchorScreen NosmaiOverlayAnchorHead NosmaiOverlayAnchorNose NosmaiOverlayAnchorLips NosmaiOverlayAnchorEyes NosmaiOverlayAnchorLeftEye NosmaiOverlayAnchorRightEye
Android
import com.nosmai.effect.api.NosmaiOverlay; NosmaiOverlay.Config config = new NosmaiOverlay.Config(); config.id = "heart"; config.anchor = NosmaiOverlay.Anchor.SCREEN; config.x = 0.5f; config.y = 0.5f; config.scale = 1.0f; config.rotation = 0.0f; config.opacity = 1.0f; NosmaiOverlay.add(bitmap, config);
Attach an overlay to a face point:
NosmaiOverlay.Config config = new NosmaiOverlay.Config(); config.id = "glasses"; config.anchor = NosmaiOverlay.Anchor.EYES; config.x = 0.0f; config.y = -0.02f; config.z = 0.0f; config.scale = 1.0f; NosmaiOverlay.add(bitmap, config);
Add from a bundled asset, a file, or a network URL:
NosmaiOverlay.addFromAsset("stickers/heart.png", config);
NosmaiOverlay.addFromFile(localPath, config);
NosmaiOverlay.addFromUrl("https://cdn.example.com/star.png", config);
Available Android anchors:
NosmaiOverlay.Anchor.SCREEN NosmaiOverlay.Anchor.HEAD NosmaiOverlay.Anchor.NOSE NosmaiOverlay.Anchor.LIPS NosmaiOverlay.Anchor.EYES NosmaiOverlay.Anchor.LEFT_EYE NosmaiOverlay.Anchor.RIGHT_EYE
Move, scale, and rotate an overlay
Update an existing overlay by its identifier. This is how a draggable, pinch-to-zoom sticker is implemented.
Flutter
await NosmaiFlutter.instance.updateOverlay( id: 'heart', x: 0.4, y: 0.6, scale: 1.3, rotation: 15.0, );
iOS
NosmaiOverlayConfig *update = [[NosmaiOverlayConfig alloc] init]; update.identifier = @"heart"; update.x = 0.4f; update.y = 0.6f; update.scale = 1.3f; update.rotation = 15.0f; [[NosmaiCore shared].effects updateOverlay:update];
Android
NosmaiOverlay.update("heart", 0.4f, 0.6f, 1.3f, 15.0f);
Update only the transform. The image is not reloaded, so continuous gesture updates stay smooth.
Animated overlays
An animated overlay plays a loop of frames. Provide a frame sequence or a GIF.
Flutter
await NosmaiFlutter.instance.addOverlay( id: 'confetti', source: NosmaiOverlaySource.sequence(confettiFramePaths), anchor: NosmaiOverlayAnchor.screen, x: 0.5, y: 0.3, );
A single animated file is also accepted:
await NosmaiFlutter.instance.addOverlay(
id: 'confetti',
source: NosmaiOverlaySource.asset('assets/stickers/confetti.gif'),
anchor: NosmaiOverlayAnchor.screen,
x: 0.5,
y: 0.3,
);
iOS
NosmaiOverlayConfig *config = [[NosmaiOverlayConfig alloc] init]; config.identifier = @"confetti"; config.anchor = NosmaiOverlayAnchorScreen; config.x = 0.5f; config.y = 0.3f; [[NosmaiCore shared].effects addOverlayFromPath:confettiPath config:config];
Android
NosmaiOverlay.Config config = new NosmaiOverlay.Config();
config.id = "confetti";
config.anchor = NosmaiOverlay.Anchor.SCREEN;
config.x = 0.5f;
config.y = 0.3f;
NosmaiOverlay.addFromAsset("stickers/confetti.gif", config);
Keep animated frames compact. A long high-resolution animation uses more memory than a short optimized loop.
Network images
An overlay image can be loaded from a network URL. The image is fetched, cached, and then composited like any other overlay.
await NosmaiFlutter.instance.addOverlay(
id: 'promo',
source: NosmaiOverlaySource.network('https://cdn.example.com/promo.png'),
anchor: NosmaiOverlayAnchor.screen,
x: 0.5,
y: 0.9,
);
Recommended behavior:
- Show a placeholder or loading state until the overlay is added.
- Reuse a downloaded image for repeated use instead of fetching it again.
- Handle a failed download and offer a retry.
- Prefer a local file or bundled asset when the same image is used often.
A network image needs a connection the first time it is fetched. Applying an already cached overlay image does not require a new download.
Remove overlays
Remove one overlay by identifier, or clear every overlay.
Flutter
await NosmaiFlutter.instance.removeOverlay('heart');
await NosmaiFlutter.instance.clearOverlays();
iOS
[[NosmaiCore shared].effects removeOverlayWithIdentifier:@"heart"]; [[NosmaiCore shared].effects clearOverlays];
Android
NosmaiOverlay.remove("heart");
NosmaiOverlay.clear();
Removing an overlay clears only that overlay. Color filters, built-in beauty, backgrounds, and .nosmai effects stay active.
How custom overlays combine with other features
Custom overlays are an independent layer, so they coexist with the other Nosmai features.
| Active together | Result |
|---|---|
Custom overlay and a color filter | Both visible |
| Custom overlay and built-in beauty or makeup | Both visible |
| Custom overlay and a background | Both visible |
Custom overlay and a .nosmai effect or beauty_effect | Both visible |
| Two custom overlays | Both visible, ordered by z |
Custom overlays are drawn above the processed content. This keeps a sticker, badge, or watermark on top of filters and effects.
Output: photo, recording, and streaming
Custom overlays are part of the processed frame, so they are automatically included in:
- captured photos
- recorded video
- live-stream output
No extra step is required to add an overlay to captured or streamed media. Before capturing, wait for the preview to be ready and for the overlay to be added.
Performance guidance
For a smooth camera:
- Keep overlay images at the resolution the design needs.
- Reuse a downloaded or decoded image instead of loading it again for each use.
- Update the transform for gestures instead of removing and adding the overlay.
- Limit the number of simultaneous animated overlays.
- Keep animated loops short and optimized.
- Test overlays while recording and live streaming, not only in preview.
- Test face-attached overlays with fast head movement.
A screen-anchored still overlay is the lightest option. Animated and face-attached overlays do more work per frame.
User interface guidance
For a movable sticker experience:
- Use a drag gesture to update
xandy. - Use a pinch gesture to update
scale. - Use a rotation gesture to update
rotation. - Give each sticker a unique identifier when it is added.
- Bring the selected sticker to the front by increasing its
z. - Provide a delete action that calls remove for that identifier.
- Debounce very frequent gesture updates if the application sends more updates than the display can present.
Test cases
Test overlays with:
- one screen sticker moved, scaled, and rotated
- several stickers at once
- a face-attached overlay on the nose, lips, eyes, and head
- the face near each screen edge
- fast head movement and head rotation
- the face leaving and returning to the view
- an animated overlay during a long session
- a network overlay with a slow connection and a failed download
- front and back camera where supported
- camera switching
- photo capture with overlays present
- recording with overlays present
- live streaming with overlays present
- repeated add and remove actions
Watch for a sticker drifting away from a face point, a delay when the face moves, incorrect mirroring on the front camera, and a drop in preview frame rate.
Troubleshooting
The overlay does not appear
Confirm that:
- the preview is ready
- the image source is valid
- the opacity is greater than
0.0 - a screen overlay is inside the visible
0.0to1.0range - a face overlay has a detected face in view
A face overlay is not attached to the face
Confirm that:
- the anchor is a face anchor, not
screen - a face is visible and reasonably lit
- the offset values are small relative to the face
The overlay is mirrored on the front camera
Front-camera preview is often mirrored. Apply mirroring in one place so the overlay, the face, and the recording use the same setting. See the mirroring notes in Errors and troubleshooting.
The overlay appears in the preview but not in the recording
Confirm the overlay was added before recording started and that the recording uses the processed Nosmai output.
Production checklist
Before release:
- initialize Nosmai before adding an overlay
- wait for preview readiness
- give each overlay a unique identifier
- keep overlay images at a reasonable resolution
- reuse downloaded or decoded images
- update transforms for gestures instead of re-adding overlays
- handle a failed network image and offer retry
- test face-attached overlays with movement and no face
- verify overlays in photo capture, recording, and live streaming
- test front and back cameras and camera switching
- test supported low-end and high-end devices
Next steps
- Read Filters and effects to understand packaged
.nosmaieffects and their slots. - Read Beauty and makeup for built-in beauty, makeup, and face shaping.
- Read Cloud filters to distribute downloadable effects.
- Read Errors and troubleshooting for camera, capture, and performance diagnosis.