Sending Notifications
Mini Apps can send notifications to users who have added the Mini App to their Farcaster client and enabled notifications.
An in-app notification is sent to a user and launches them into the app
Overview
At a high-level notifications work like so:
- when a user enables notifications for your app, the Farcaster client (i.e. Warpcast) hosting your app will generate a notification token for that user and send it to your server
- to send a notification to a user, make a request to host's servers with the notification token and content
- if a user later disables notifications, you'll receive another event indicating the user is unsubscribed and the notification token is no longer valid
Steps
Listen for events
You'll need a server to receive webhook events and a database to store notification tokens for users:
- Managed - If you'd rather stay focused on your app, use
Neynar to manage notification tokens on your behalf:
Setup a managed notifications server with Neynar. - Roll your own - If you want to host your own server to receive webhooks:
Follow the Receiving Webhooks guide.
Add your webhook URL in farcaster.json
If you haven't already, follow the Publishing your app guide to host a
farcaster.json
on your app's domain.
Define the webhookUrl
property in your app's configuration in farcaster.json
:
{
"accountAssociation": {
"header": "eyJmaWQiOjU0NDgsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHg2MWQwMEFENzYwNjhGOEQ0NzQwYzM1OEM4QzAzYUFFYjUxMGI1OTBEIn0",
"payload": "eyJkb21haW4iOiJleGFtcGxlLmNvbSJ9",
"signature": "MHg3NmRkOWVlMjE4OGEyMjliNzExZjUzOTkxYTc1NmEzMGZjNTA3NmE5OTU5OWJmOWFmYjYyMzAyZWQxMWQ2MWFmNTExYzlhYWVjNjQ3OWMzODcyMTI5MzA2YmJhYjdhMTE0MmRhMjA4MmNjNTM5MTJiY2MyMDRhMWFjZTY2NjE5OTFj"
},
"frame": {
"version": "1",
"name": "Example App",
"iconUrl": "https://example.com/icon.png",
"homeUrl": "https://example.com",
"imageUrl": "https://example.com/image.png",
"buttonTitle": "Check this out",
"splashImageUrl": "https://example.com/splash.png",
"splashBackgroundColor": "#eeccff",
"webhookUrl": "https://example.com/api/webhook"
}
}
Get users to add your app
For a Mini App to send notifications, it needs to first be added by a user to their Farcaster client and for notifications to be enabled (these will be enabled by default).
Use the addFrame action while a user is using your app to prompt them to add it:
Save the notification tokens
When notifications are enabled, the Farcaster client generates a unique
notification token for the user. This token is sent webhook endpoint along with
a url
that the app should call to send a notification.
The token
and url
need to be securely saved to database so they can be
looked up when you want to send a notification to a particular user.
Send a notification
Once you have a notification token for a user, you can send them a notification
by sending a POST
request the url
associated with that token.
Example code to send a notification
Here are the types:
export const sendNotificationRequestSchema = z.object({
notificationId: z.string().max(128),
title: z.string().max(32),
body: z.string().max(128),
targetUrl: z.string().max(256),
tokens: z.string().array().max(100),
});
export type SendNotificationRequest = z.infer<
typeof sendNotificationRequestSchema
>;
export const sendNotificationResponseSchema = z.object({
result: z.object({
successfulTokens: z.array(z.string()),
invalidTokens: z.array(z.string()),
rateLimitedTokens: z.array(z.string()),
}),
});
export type SendNotificationResponse = z.infer<
typeof sendNotificationResponseSchema
>;
The request is a JSON consisting of:
notificationId
: a string (max size 128) that serves as an idempotency key and will be passed back to the app via context. A Farcaster client should deliver only one notification per user pernotificationId
, even if called multiple times.title
: title of the notification, max 32 charactersbody
: body of the notification, max 128 characterstargetUrl
: the target app URL to open when a user clicks the notification. It must match the domain for which the notification token was issued. Max 256 characters.tokens
: an array of tokens (for thaturl
) to send the notification to. Max 100 per call.
Note that client servers may impose rate limits per token
. Warpcast enforces the following rate limits:
- 1 notification per 30 seconds per
token
- 100 notifications per day per
token
The response from the client server must be an HTTP 200 OK, with a result
object that contains 3 arrays:
successfulTokens
: tokens for which the notification succeeded, including those for which the request is a duplicate (samenotificationId
used before)invalidTokens
: tokens which are no longer valid and should never be used again. This could happen if the user disabled notifications.rateLimitedTokens
: tokens for which the rate limit was exceeded. You can try later.
Once a user clicks the notification, the Farcaster client will:
- Open
targetUrl
- Set the
context.location
to aFrameLocationNotificationContext
export type FrameLocationNotificationContext = {
type: 'notification';
notification: {
notificationId: string;
title: string;
body: string;
};
};
Receiving webhooks
Users can add and configure notification settings Mini Apps within their Farcaster client. When this happens Farcaster clients will send events your server that include data relevant to the event.
This allows your app to:
- keep track of what users have added or removed your app
- securely receive tokens that can be used to send notifications to your users
Events
frame_added
Sent when the user adds the Mini App to their Farcaster client (whether or not
this was triggered by an addFrame()
prompt).
The optional notificationDetails
object provides the token
and url
if the
client equates adding to enabling notifications (Warpcast does this).
Payload
{
"event": "frame_added",
"notificationDetails": {
"url": "https://api.warpcast.com/v1/frame-notifications",
"token": "a05059ef2415c67b08ecceb539201cbc6"
}
}
frame_removed
Sent when a user removes a mini app, which means that any notification tokens for that fid and client app (based on signer requester) should be considered invalid:
Payload
{
"event": "frame_removed"
}
notifications_disabled
Sent when a user disables notifications from e.g. a settings panel in the client app. Any notification tokens for that fid and client app (based on signer requester) should be considered invalid:
Payload
{
"event": "notifications_disabled"
}
notifications_enabled
Sent when a user enables notifications (e.g. after disabling them). The payload
includes a new token
and url
:
Payload
{
"event": "notifications_enabled",
"notificationDetails": {
"url": "https://api.warpcast.com/v1/frame-notifications",
"token": "a05059ef2415c67b08ecceb539201cbc6"
}
}
Handling events
Farcaster clients will POST events to the webhookUrl
specified in your farcaster.json
.
Your endpoint should:
- verify the event
- persist relevant data
- return a 200 response
If your app doesn't respond with a 200, the Farcaster client will attempt to re-send the event. The exact number of retries is up to each client.
Verifying events
Events are signed by the app key of a user with a JSON Farcaster Signature. This allows Mini Apps to verify the Farcaster client that generated the notification and the Farcaster user they generated it for.
The
@farcaster/frame-node
library provides a helper for verifying events. To use it, you'll need to supply a validation
function that can check the signatures against the latest Farcaster network state.
An implementation that uses Neynar is provided. You can sign up and get
an API key on their free tier. Make sure to set NEYNAR_API_KEY
environment variable.
Example
import {
ParseWebhookEvent,
parseWebhookEvent,
verifyAppKeyWithNeynar,
} from "@farcaster/frame-node";
try {
const data = await parseWebhookEvent(requestJson, verifyAppKeyWithNeynar);
} catch (e: unknown) {
const error = e as ParseWebhookEvent.ErrorType;
switch (error.name) {
case "VerifyJsonFarcasterSignature.InvalidDataError":
case "VerifyJsonFarcasterSignature.InvalidEventDataError":
// The request data is invalid
case "VerifyJsonFarcasterSignature.InvalidAppKeyError":
// The app key is invalid
case "VerifyJsonFarcasterSignature.VerifyAppKeyError":
// Internal error verifying the app key (caller may want to try again)
}
}
Reference implementation
For a complete example, check out the Mini App V2 Demo has all of the above:
- Handles webhooks leveraging the
@farcaster/frame-node
library that makes this very easy - Saves notification tokens to Redis
- Sends notifications