How to Send Structured Payloads
Send rich media and file attachments as typed data objects, with automatic chunking and complete payload delivery.
Images, Audio, Documents
Send rich media and file attachments through send() using typed data objects. The SDK serializes your payload, chunks large content automatically, and delivers a complete message to onMessage.
Recommended Payload Types
| data.type | Typical fields | Use case |
|---|---|---|
| text | text | Chat messages |
| image | content (bytes) | Photo sharing |
| audio | content, durationMs | Voice notes |
| doc | content, fileName, mimeType | File attachments |
DNotifier does not enforce a fixed enum — define conventions in your app and handle them in onMessage.
Sending Flow
read file bytes locally
│
▼
send({ data: { type: "image", content: bytes } })
│
▼
SDK chunks if > messageSizeLimit
│
▼
receiver onMessage → payload.toJSON() or raw()Large files are split automatically. Your handler always receives a reassembled payload.
Receiving Structured Payloads
In onMessage, branch on body.type:
onMessage: (msg) => {
const body = msg.payload.toJSON();
if (body?.type === "image") {
// body.content — image bytes
} else if (body?.type === "audio") {
// body.content, body.durationMs
} else if (body?.type === "doc") {
// body.content, body.fileName, body.mimeType
}
},JavaScript / TypeScript
Send images, audio, and documents via send() with typed data objects.
Image
import { readFileSync } from "fs";
import WebSocket from "ws";
import { DNotifier } from "@dnotifier-realtime/dnotifier";
const imageBytes = readFileSync("./photo.png");
const notifier = new DNotifier({
appId: process.env.DNOTIFIER_APP_ID,
secret: process.env.DNOTIFIER_SECRET,
transport: "ws",
userId: "user-alice",
WebSocketImpl: WebSocket,
onConnected: () => {},
onMessage: (msg) => {
const body = msg.payload.toJSON();
if (body?.type === "image") {
console.log("Received image, bytes:", body.content?.length);
}
},
onDisconnected: () => {},
});
await notifier.connect();
await notifier.send({
senderId: "user-alice",
receiverId: "user-bob",
data: {
type: "image",
content: imageBytes,
},
});Browser Image From File Input
const file = document.querySelector("input[type=file]").files[0];
const arrayBuffer = await file.arrayBuffer();
const imageBytes = new Uint8Array(arrayBuffer);
await notifier.send({
senderId: myUserId,
receiverId: peerUserId,
data: {
type: "image",
content: imageBytes,
fileName: file.name,
mimeType: file.type,
},
});Audio
import { readFileSync } from "fs";
const audioBytes = readFileSync("./voice-note.m4a");
await notifier.send({
senderId: "user-alice",
receiverId: "user-bob",
data: {
type: "audio",
content: audioBytes,
durationMs: 12500,
mimeType: "audio/mp4",
},
});Document
import { readFileSync } from "fs";
const docBytes = readFileSync("./report.pdf");
await notifier.send({
senderId: "user-alice",
receiverId: "user-bob",
data: {
type: "doc",
content: docBytes,
fileName: "report.pdf",
mimeType: "application/pdf",
},
});Receiving and Displaying
onMessage: (msg) => {
const body = msg.payload.toJSON();
switch (body?.type) {
case "image": {
const blob = new Blob(
[body.content],
{ type: body.mimeType ?? "image/png" },
);
const url = URL.createObjectURL(blob);
showImagePreview(url);
break;
}
case "audio":
playAudioBuffer(body.content, body.mimeType);
break;
case "doc":
offerDownload(body.content, body.fileName, body.mimeType);
break;
}
},Size Limits
Check notifier.messageSizeLimit after connect(). Payloads larger than this limit are chunked automatically — you do not split files manually.
await notifier.connect();
console.log("Max chunk size:", notifier.messageSizeLimit);Dart / Flutter
Send images, audio, and documents via send() with typed data objects.
Image
import 'dart:io';
import 'package:dnotifier/dnotifier.dart';
Future<void> sendImage(DNotifier notifier) async {
final imageBytes = await File('path/to/photo.png').readAsBytes();
await notifier.send(
senderId: 'user-alice',
receiverId: 'user-bob',
data: {
'type': 'image',
'content': imageBytes,
},
);
}Flutter Image Picker
import 'package:image_picker/image_picker.dart';
Future<void> sendPickedImage(DNotifier notifier, XFile file) async {
final bytes = await file.readAsBytes();
await notifier.send(
senderId: myUserId,
receiverId: peerUserId,
data: {
'type': 'image',
'content': bytes,
'fileName': file.name,
'mimeType': 'image/jpeg',
},
);
}Audio
import 'dart:io';
Future<void> sendAudio(DNotifier notifier) async {
final audioBytes = await File('path/to/voice-note.m4a').readAsBytes();
await notifier.send(
senderId: 'user-alice',
receiverId: 'user-bob',
data: {
'type': 'audio',
'content': audioBytes,
'durationMs': 12500,
'mimeType': 'audio/mp4',
},
);
}Document
import 'dart:io';
Future<void> sendDocument(DNotifier notifier) async {
final docBytes = await File('path/to/report.pdf').readAsBytes();
await notifier.send(
senderId: 'user-alice',
receiverId: 'user-bob',
data: {
'type': 'doc',
'content': docBytes,
'fileName': 'report.pdf',
'mimeType': 'application/pdf',
},
);
}Receiving Structured Payloads
onMessage: (msg) {
final body = msg.payload.toJSON();
if (body is! Map) return;
switch (body['type']) {
case 'image':
final bytes = body['content'];
if (bytes is List<int>) {
showImagePreview(bytes);
}
break;
case 'audio':
playAudio(body['content'], body['mimeType'] as String?);
break;
case 'doc':
saveAndOpenFile(
body['content'],
body['fileName'] as String?,
body['mimeType'] as String?,
);
break;
}
},Size Limits
await notifier.connect();
print('Max chunk size: ${notifier.messageSizeLimit}');Payloads larger than messageSizeLimit are chunked automatically.
Python
Send images, audio, and documents via send() with typed data objects.
Image
from pathlib import Path
from dnotifier import DNotifier
async def send_image(notifier: DNotifier):
image_bytes = Path("path/to/photo.png").read_bytes()
await notifier.send(
sender_id="user-alice",
receiver_id="user-bob",
data={"type": "image", "content": image_bytes},
)With File Metadata
async def send_image_with_meta(notifier: DNotifier, file_path: str):
image_bytes = Path(file_path).read_bytes()
await notifier.send(
sender_id=my_user_id,
receiver_id=peer_user_id,
data={
"type": "image",
"content": image_bytes,
"fileName": Path(file_path).name,
"mimeType": "image/jpeg",
},
)Audio
from pathlib import Path
async def send_audio(notifier: DNotifier):
audio_bytes = Path("path/to/voice-note.m4a").read_bytes()
await notifier.send(
sender_id="user-alice",
receiver_id="user-bob",
data={
"type": "audio",
"content": audio_bytes,
"durationMs": 12500,
"mimeType": "audio/mp4",
},
)Document
from pathlib import Path
async def send_document(notifier: DNotifier):
doc_bytes = Path("path/to/report.pdf").read_bytes()
await notifier.send(
sender_id="user-alice",
receiver_id="user-bob",
data={
"type": "doc",
"content": doc_bytes,
"fileName": "report.pdf",
"mimeType": "application/pdf",
},
)Receiving Structured Payloads
def on_message(msg):
body = msg.payload.to_json()
if not isinstance(body, dict):
return
msg_type = body.get("type")
if msg_type == "image":
content = body.get("content")
if isinstance(content, (bytes, bytearray)):
show_image_preview(content)
elif msg_type == "audio":
play_audio(body.get("content"), body.get("mimeType"))
elif msg_type == "doc":
save_and_open_file(
body.get("content"),
body.get("fileName"),
body.get("mimeType"),
)Size Limits
await notifier.connect()
print(f"Max chunk size: {notifier.message_size_limit}")Payloads larger than message_size_limit are chunked automatically.