Tutorial 5 of 5

How to Send and Receive Your First Message

Send a 1:1 realtime message over WebSocket and receive it on another client — with runnable examples in JavaScript, Dart/Flutter, and Python.

12 min read~3 min video

After a successful connection, you can send a 1:1 realtime message to another user. This tutorial explains the concept, then walks through a complete, runnable example for each supported language.

What You Are Building

A minimal flow with two logical users:

user-alice (your SDK)                    user-bob (another client)
       │                                          │
       │  send({ receiverId: "user-bob", ... })   │
       ├────────────────────────────────────►│
       │                                          │
       │◄────────────────────────────────────┤
       │         onMessage on bob's client          │

Both users connect with the same appId but different userId values. Messages route by senderId and receiverId.

Requirements

  • transport: "ws" — realtime send/receive uses WebSocket
  • connect() completed — isConnected === true
  • Receiver exists conceptually — the receiver does not need to be online; DNotifier delivers when they connect (subject to plan and app rules)

The send() Call

All SDKs expose a similar send() shape:

FieldDescription
senderIdMust match the connecting user's id (your userId)
receiverIdTarget user's id (single recipient)
dataJSON-serializable payload — typically { type: "text", text: "..." }
saveHistoryOptional; default true — persist for chat history APIs

Example payload:

{
  "type": "text",
  "text": "Hello from DNotifier!"
}

Use any type string your app understands (text, image, audio, doc, custom types).

Receiving Messages

Incoming messages arrive on the onMessage callback registered at construction time. Each message has:

  • metadata — sender, timestamp, id, type
  • payload — body with helpers like toJSON()

Test with Two Clients

  • Run two terminal processes (or two browser tabs)
  • Connect as user-alice in one and user-bob in the other
  • Send from alice to bob and watch bob's onMessage fire

JavaScript / TypeScript

Send your first 1:1 realtime text message after connecting over WebSocket. This example assumes you completed First Connection.

Complete Example

import WebSocket from "ws";
import { DNotifier } from "@dnotifier-realtime/dnotifier";

const MY_USER_ID = "user-alice";
const PEER_USER_ID = "user-bob";

const notifier = new DNotifier({
  appId: process.env.DNOTIFIER_APP_ID,
  secret: process.env.DNOTIFIER_SECRET,
  transport: "ws",
  userId: MY_USER_ID,
  WebSocketImpl: WebSocket,
  onConnected: async () => {
    console.log("Connected as", MY_USER_ID);

    await notifier.send({
      senderId: MY_USER_ID,
      receiverId: PEER_USER_ID,
      data: {
        type: "text",
        text: "Hello from DNotifier!",
      },
    });

    console.log("Message sent to", PEER_USER_ID);
  },
  onMessage: (msg) => {
    const body = msg.payload.toJSON();
    console.log(`[${msg.metadata.sender}]`, body);
  },
  onDisconnected: () => {
    console.log("Disconnected");
  },
});

await notifier.connect();

Browser Variant

import { DNotifier } from "@dnotifier-realtime/dnotifier";

const MY_USER_ID = "user-alice";
const PEER_USER_ID = "user-bob";

const notifier = new DNotifier({
  appId: import.meta.env.VITE_DNOTIFIER_APP_ID,
  secret: import.meta.env.VITE_DNOTIFIER_SECRET,
  transport: "ws",
  userId: MY_USER_ID,
  onConnected: () => console.log("Connected"),
  onMessage: (msg) => console.log(msg.payload.toJSON()),
  onDisconnected: () => {},
});

await notifier.connect();

await notifier.send({
  senderId: MY_USER_ID,
  receiverId: PEER_USER_ID,
  data: { type: "text", text: "Hello from DNotifier!" },
});

Send After Connect (Decoupled)

If you prefer not to send inside onConnected:

await notifier.connect();

await notifier.send({
  senderId: "user-alice",
  receiverId: "user-bob",
  data: {
    type: "text",
    text: "Hello from DNotifier!",
  },
  saveHistory: true, // default — set false to skip chat history persistence
});

Echo Test (Single Process)

Run two scripts in separate terminals to verify delivery.

Terminal 1 — bob (receiver):

// receive.js — user-bob listens
import WebSocket from "ws";
import { DNotifier } from "@dnotifier-realtime/dnotifier";

const notifier = new DNotifier({
  appId: process.env.DNOTIFIER_APP_ID,
  secret: process.env.DNOTIFIER_SECRET,
  transport: "ws",
  userId: "user-bob",
  WebSocketImpl: WebSocket,
  onConnected: () => console.log("Bob is online"),
  onMessage: (msg) => console.log("Bob received:", msg.payload.toJSON()),
  onDisconnected: () => {},
});

await notifier.connect();

Terminal 2 — alice (sender): use the complete example at the top of this section.

Bob's terminal should print:

Bob received: { type: 'text', text: 'Hello from DNotifier!' }

TypeScript

await notifier.send({
  senderId: MY_USER_ID,
  receiverId: PEER_USER_ID,
  data: {
    type: "text",
    text: "Hello from DNotifier!",
  } satisfies { type: string; text: string },
});

Troubleshooting

IssueCheck
Send throws before connectAwait connect() first; confirm isConnected
Bob never receivesBob must be connected with same appId; verify receiverId spelling
Empty payloadEnsure data is JSON-serializable
Auth works but send failsConfirm WebSocket transport, not HTTP

Dart / Flutter

Send your first 1:1 realtime text message after connecting over WebSocket. This example assumes you completed First Connection.

Complete Example

import 'package:dnotifier/dnotifier.dart';

const myUserId = 'user-alice';
const peerUserId = 'user-bob';

Future<void> main() async {
  final notifier = DNotifier(
    appId: 'your-app-id',
    secret: 'your-app-secret',
    transport: 'ws',
    userId: myUserId,
    onConnected: () async {
      print('Connected as $myUserId');

      await notifier.send(
        senderId: myUserId,
        receiverId: peerUserId,
        data: {
          'type': 'text',
          'text': 'Hello from DNotifier!',
        },
      );

      print('Message sent to $peerUserId');
    },
    onMessage: (DNotifierMessage msg) {
      print('[${msg.metadata.sender}] ${msg.payload.toJSON()}');
    },
    onDisconnected: ({code, reason}) {
      print('Disconnected: $reason');
    },
  );

  await notifier.connect();
}

Replace credentials with your dashboard values or compile-time defines.

Run

dart run bin/send_first_message.dart

Send After Connect (Decoupled)

await notifier.connect();

await notifier.send(
  senderId: 'user-alice',
  receiverId: 'user-bob',
  data: {
    'type': 'text',
    'text': 'Hello from DNotifier!',
  },
  saveHistory: true, // default — set false to skip chat history persistence
);

Flutter Button Example

ElevatedButton(
  onPressed: () async {
    if (!notifier.isConnected) return;
    await notifier.send(
      senderId: myUserId,
      receiverId: peerUserId,
      data: {'type': 'text', 'text': 'Hello from Flutter!'},
    );
  },
  child: const Text('Send message'),
)

Echo Test (Two Processes)

Process 1 — bob listens:

import 'package:dnotifier/dnotifier.dart';

Future<void> main() async {
  final bob = DNotifier(
    appId: 'your-app-id',
    secret: 'your-app-secret',
    transport: 'ws',
    userId: 'user-bob',
    onConnected: () => print('Bob is online'),
    onMessage: (msg) => print('Bob received: ${msg.payload.toJSON()}'),
  );
  await bob.connect();
}

Process 2 — alice sends: use the complete example at the top of this section.

Expected on bob's console:

Bob received: {type: text, text: Hello from DNotifier!}

Troubleshooting

IssueCheck
StateError: Not connectedAwait connect() before send()
Receiver gets nothingReceiver must use same appId and be connected
ArgumentError: receiverId or receiverIds requiredPass receiverId or receiverIds
Auth OK but no deliveryUse transport: 'ws', not 'http'

Python

Send your first 1:1 realtime text message after connecting over WebSocket. This example assumes you completed First Connection.

Complete Example

import asyncio
from dnotifier import DNotifier

MY_USER_ID = "user-alice"
PEER_USER_ID = "user-bob"

async def on_connected(notifier: DNotifier):
    print(f"Connected as {MY_USER_ID}")
    await notifier.send(
        sender_id=MY_USER_ID,
        receiver_id=PEER_USER_ID,
        data={"type": "text", "text": "Hello from DNotifier!"},
    )
    print(f"Message sent to {PEER_USER_ID}")

async def main():
    notifier = DNotifier(
        app_id="your-app-id",
        secret="your-app-secret",
        transport="ws",
        user_id=MY_USER_ID,
        on_connected=lambda: asyncio.create_task(on_connected(notifier)),
        on_message=lambda msg: print(f"[{msg.metadata.sender}] {msg.payload.to_json()}"),
        on_disconnected=lambda code=None, reason=None: print(f"Disconnected: {reason}"),
    )
    await notifier.connect()
    await asyncio.sleep(3600)  # keep alive for incoming messages

asyncio.run(main())

Replace credentials with your dashboard values or environment variables.

Run

python send_first_message.py

Send After Connect (Decoupled)

await notifier.connect()

await notifier.send(
    sender_id="user-alice",
    receiver_id="user-bob",
    data={"type": "text", "text": "Hello from DNotifier!"},
    save_history=True,  # default — set False to skip chat history persistence
)

Echo Test (Two Processes)

Process 1 — bob listens:

import asyncio
from dnotifier import DNotifier

async def main():
    bob = DNotifier(
        app_id="your-app-id",
        secret="your-app-secret",
        transport="ws",
        user_id="user-bob",
        on_connected=lambda: print("Bob is online"),
        on_message=lambda msg: print(f"Bob received: {msg.payload.to_json()}"),
    )
    await bob.connect()
    await asyncio.sleep(3600)

asyncio.run(main())

Process 2 — alice sends: use the complete example at the top of this section.

Expected on bob's console:

Bob received: {'type': 'text', 'text': 'Hello from DNotifier!'}

Troubleshooting

IssueCheck
RuntimeError: Not connectedAwait connect() before send()
Receiver gets nothingReceiver must use same app_id and be connected
ValueError: receiver_id or receiver_ids requiredPass receiver_id or receiver_ids
Auth OK but no deliveryUse transport="ws", not "http"

Watch: How to Send and Receive Your First Message

Same steps as above — use whichever format you prefer.

DNotifier Tutorial

Tutorial 5 of 5

  1. Tutorial 1How to Create a New Project
  2. Tutorial 2How to Install the DNotifier SDK
  3. Tutorial 3How to Choose a Transport
  4. Tutorial 4How to Make Your First Connection
  5. Tutorial 5How to Send and Receive Your First Message
← How to Make Your First ConnectionMore tutorials coming soon