> ## Documentation Index
> Fetch the complete documentation index at: https://base-a060aa97-danc-alpha-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# useNotification (coming soon)

> Send notifications via a backend proxy to users who saved your Mini App (Coming Soon)

Defined in [@coinbase/onchainkit](https://github.com/coinbase/onchainkit)

<Warning>
  Notifications are not yet available in Base App but are coming soon. This documentation describes the upcoming API that will be available when notifications are fully deployed.
</Warning>

ebcbglkhecg

<Info>
  Allows Mini Apps to send push notifications to users who have saved your app. Notifications require a backend proxy route to handle the actual delivery and enforce rate limiting.
</Info>

## Parameters

<ParamField body="options" type="NotificationOptions" required>
  Configuration object for the notification to send.

  <Expandable title="NotificationOptions properties">
    <ParamField body="title" type="string" required>
      The notification title (maximum 100 characters).
    </ParamField>

    <ParamField body="body" type="string" required>
      The notification message body (maximum 500 characters).
    </ParamField>

    <ParamField body="targetFid" type="string" optional>
      Specific user FID to send notification to. If not provided, sends to all users who saved your Mini App.
    </ParamField>

    <ParamField body="actionUrl" type="string" optional>
      URL to open when notification is tapped. Defaults to your Mini App URL.
    </ParamField>
  </Expandable>
</ParamField>

## Required Backend Setup

Notifications require a backend proxy route to handle delivery and rate limiting:

<RequestExample>
  ```typescript app/api/minikit/notifications/route.ts
  // /api/minikit/notifications
  import { NextRequest, NextResponse } from 'next/server';

  const FARCASTER_API_URL = 'https://api.farcaster.xyz';
  const MAX_NOTIFICATIONS_PER_HOUR = 10;

  interface NotificationRequest {
    title: string;
    body: string;
    targetFid?: string;
    actionUrl?: string;
  }

  export async function POST(request: NextRequest) {
    try {
      const { title, body, targetFid, actionUrl }: NotificationRequest = await request.json();
      
      // Validate request
      if (!title || !body) {
        return NextResponse.json(
          { error: 'Title and body are required' },
          { status: 400 }
        );
      }
      
      if (title.length > 100 || body.length > 500) {
        return NextResponse.json(
          { error: 'Title or body too long' },
          { status: 400 }
        );
      }
      
      // Check rate limits (implement your own rate limiting logic)
      const isRateLimited = await checkRateLimit(request);
      if (isRateLimited) {
        return NextResponse.json(
          { error: 'Rate limit exceeded' },
          { status: 429 }
        );
      }
      
      // Forward to Farcaster notification API
      const response = await fetch(`${FARCASTER_API_URL}/notifications`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.FARCASTER_API_KEY}`,
        },
        body: JSON.stringify({
          title,
          body,
          targetFid,
          actionUrl: actionUrl || process.env.MINI_APP_URL,
          appId: process.env.MINI_APP_ID,
        }),
      });
      
      if (!response.ok) {
        throw new Error(`Notification API error: ${response.status}`);
      }
      
      const result = await response.json();
      return NextResponse.json(result);
      
    } catch (error) {
      console.error('Notification error:', error);
      return NextResponse.json(
        { error: 'Failed to send notification' },
        { status: 500 }
      );
    }
  }

  async function checkRateLimit(request: NextRequest): Promise<boolean> {
    // Implement your rate limiting logic here
    // Consider using Redis or a database to track notification counts
    // Return true if rate limit is exceeded
    return false;
  }
  ```

  ```python server.py
  from fastapi import FastAPI, HTTPException, BackgroundTasks
  from pydantic import BaseModel
  import httpx
  import os
  from typing import Optional

  app = FastAPI()

  class NotificationRequest(BaseModel):
      title: str
      body: str
      targetFid: Optional[str] = None
      actionUrl: Optional[str] = None

  FARCASTER_API_URL = "https://api.farcaster.xyz"
  MAX_NOTIFICATIONS_PER_HOUR = 10

  @app.post("/api/minikit/notifications")
  async def send_notification(
      notification: NotificationRequest,
      background_tasks: BackgroundTasks
  ):
      # Validate input
      if len(notification.title) > 100:
          raise HTTPException(status_code=400, detail="Title too long")
      
      if len(notification.body) > 500:
          raise HTTPException(status_code=400, detail="Body too long")
      
      # Check rate limits
      if await is_rate_limited():
          raise HTTPException(status_code=429, detail="Rate limit exceeded")
      
      # Prepare payload
      payload = {
          "title": notification.title,
          "body": notification.body,
          "targetFid": notification.targetFid,
          "actionUrl": notification.actionUrl or os.getenv("MINI_APP_URL"),
          "appId": os.getenv("MINI_APP_ID"),
      }
      
      # Send to Farcaster API
      async with httpx.AsyncClient() as client:
          response = await client.post(
              f"{FARCASTER_API_URL}/notifications",
              json=payload,
              headers={
                  "Authorization": f"Bearer {os.getenv('FARCASTER_API_KEY')}",
                  "Content-Type": "application/json",
              }
          )
          
          if response.status_code != 200:
              raise HTTPException(
                  status_code=500, 
                  detail="Failed to send notification"
              )
          
          return response.json()

  async def is_rate_limited() -> bool:
      # Implement rate limiting logic
      return False
  ```
</RequestExample>

## Frontend Usage

<RequestExample>
  ```tsx components/GameCompletion.tsx
  import { useNotification } from '@coinbase/onchainkit/minikit';
  import { useState } from 'react';

  export default function GameCompletion({ playerStats }) {
    const [isNotifying, setIsNotifying] = useState(false);
    const sendNotification = useNotification();

    const notifyAchievement = async () => {
      setIsNotifying(true);
      
      try {
        await sendNotification({
          title: "🎮 New Achievement Unlocked!",
          body: `You just beat ${playerStats.level} with a score of ${playerStats.score}! Can your friends do better?`,
          actionUrl: `${window.location.origin}/challenge/${playerStats.gameId}`
        });
        
        console.log('Achievement notification sent!');
      } catch (error) {
        console.error('Failed to send notification:', error);
      } finally {
        setIsNotifying(false);
      }
    };

    return (
      <div className="game-completion">
        <h2>🏆 Level Complete!</h2>
        <p>Score: {playerStats.score}</p>
        
        <button 
          onClick={notifyAchievement}
          disabled={isNotifying}
          className="notify-btn"
        >
          {isNotifying ? 'Sending...' : 'Share Achievement'}
        </button>
      </div>
    );
  }
  ```

  ```tsx components/TournamentScheduler.tsx
  import { useNotification } from '@coinbase/onchainkit/minikit';
  import { useEffect, useState } from 'react';

  export default function TournamentScheduler({ tournament }) {
    const sendNotification = useNotification();
    const [reminderSet, setReminderSet] = useState(false);

    const scheduleReminder = async () => {
      try {
        await sendNotification({
          title: "🏆 Tournament Starting Soon!",
          body: `${tournament.name} begins in 15 minutes. Join now to compete for prizes!`,
          actionUrl: `${window.location.origin}/tournament/${tournament.id}`
        });
        
        setReminderSet(true);
      } catch (error) {
        console.error('Failed to schedule reminder:', error);
      }
    };

    return (
      <div className="tournament-card">
        <h3>{tournament.name}</h3>
        <p>Starts: {tournament.startTime}</p>
        <p>Prize Pool: {tournament.prizePool}</p>
        
        <button 
          onClick={scheduleReminder}
          disabled={reminderSet}
          className="reminder-btn"
        >
          {reminderSet ? '✅ Reminder Set' : '🔔 Remind Me'}
        </button>
      </div>
    );
  }
  ```

  ```tsx components/SocialUpdates.tsx
  import { useNotification, useMiniKit } from '@coinbase/onchainkit/minikit';

  export default function SocialUpdates({ userFid }) {
    const { context } = useMiniKit();
    const sendNotification = useNotification();

    const notifyFriends = async (updateType, details) => {
      try {
        await sendNotification({
          title: getNotificationTitle(updateType),
          body: getNotificationBody(updateType, details),
          // Don't specify targetFid to notify all saved users
        });
      } catch (error) {
        console.error('Failed to send social update:', error);
      }
    };

    const getNotificationTitle = (type) => {
      switch (type) {
        case 'high_score':
          return '🎯 New High Score!';
        case 'level_up':
          return '⬆️ Level Up!';
        case 'challenge':
          return '⚡ New Challenge!';
        default:
          return '📢 Mini App Update';
      }
    };

    const getNotificationBody = (type, details) => {
      switch (type) {
        case 'high_score':
          return `Someone just scored ${details.score} points! Can you beat it?`;
        case 'level_up':
          return `A player reached level ${details.level}! Join the competition.`;
        case 'challenge':
          return `New daily challenge available with ${details.reward} rewards!`;
        default:
          return 'Check out the latest updates in the Mini App!';
      }
    };

    return (
      <div className="social-updates">
        <button onClick={() => notifyFriends('high_score', { score: 9999 })}>
          Share High Score
        </button>
        <button onClick={() => notifyFriends('challenge', { reward: '100 coins' })}>
          Announce Challenge
        </button>
      </div>
    );
  }
  ```
</RequestExample>

## Rate Limiting Guidelines

### Recommended Limits

* **Per user**: Maximum 10 notifications per hour
* **Per app**: Maximum 1000 notifications per hour
* **Burst protection**: Maximum 3 notifications per minute

### Implementation Strategy

```typescript lib/rate-limit.ts
// Redis-based rate limiting example
import Redis from 'ioredis';

const redis = new Redis(process.env.REDIS_URL);

async function checkRateLimit(appId: string, userFid?: string): Promise<boolean> {
  const now = Date.now();
  const hourKey = `notifications:${appId}:${Math.floor(now / 3600000)}`;
  
  // Check app-wide limits
  const appCount = await redis.incr(hourKey);
  await redis.expire(hourKey, 3600);
  
  if (appCount > 1000) {
    return true; // Rate limited
  }
  
  // Check per-user limits if targeting specific user
  if (userFid) {
    const userKey = `notifications:${appId}:user:${userFid}:${Math.floor(now / 3600000)}`;
    const userCount = await redis.incr(userKey);
    await redis.expire(userKey, 3600);
    
    if (userCount > 10) {
      return true; // Rate limited
    }
  }
  
  return false; // Not rate limited
}
```

## Best Practices

### Content Guidelines

* **Be relevant**: Only send notifications related to user activity or time-sensitive events
* **Personalize**: Use user-specific information when available
* **Clear value**: Ensure each notification provides clear value to the recipient
* **Timing**: Send notifications at appropriate times (avoid late night/early morning)

### Technical Considerations

* **Error handling**: Always handle notification failures gracefully
* **Retry logic**: Implement exponential backoff for failed deliveries
* **Analytics**: Track notification delivery rates and user engagement
* **Privacy**: Respect user notification preferences and provide opt-out mechanisms

### User Experience

* **Frequency control**: Allow users to control notification frequency
* **Category filters**: Let users choose types of notifications they want
* **Action relevance**: Ensure notification action URLs are contextually relevant

<Warning>
  Excessive or irrelevant notifications may lead to users removing your Mini App. Always prioritize user experience over engagement metrics.
</Warning>

<Info>
  When implemented thoughtfully, notifications can significantly increase user engagement and retention for your Mini App. Focus on providing genuine value with each notification sent.
</Info>
