# Subscriber Deleted Hook

> Remove personal data you keep outside Broadcast when a subscriber is deleted. Full example and common mistakes.

Source: https://sendbroadcast.net/docs/plugins-hook-subscriber-deleted

> Coming in Broadcast 3.0. Until then, this page applies only to the Upcoming (edge) build.

Use this hook to clean up when a subscriber is deleted. It matters most when your plugin sent a person's data to another service, or saved it in the shared store.

**You may not need it.** Data in `ctx.store.forSubscriber` is deleted for you, and so are that person's plugin events. Add this hook only for data that Broadcast cannot see.

## How it works

When a subscriber is deleted, a background job calls `onSubscriberDeleted`. By then the subscriber is gone.

## Full example: remove a contact from a CRM

`manifest.json`:

```json
{
  "id": "local.crm-forget",
  "name": "CRM forget",
  "version": "1.0.0",
  "requires": { "broadcast": ">=3.0.0 <4.0.0", "pluginApi": "1" },
  "permissions": {
    "network": ["api.example-crm.com"]
  },
  "hooks": {
    "onSubscriberDeleted": true
  },
  "settings": {
    "api_key": { "type": "string", "label": "CRM API key", "secret": true, "required": true }
  }
}
```

`dist/main.js`:

```javascript
export default definePlugin({
  async onSubscriberDeleted({ email }, ctx) {
    const apiKey = await ctx.settings.secret("api_key");
    const response = await fetch(`https://api.example-crm.com/v1/contacts/${encodeURIComponent(email)}`, {
      method: "DELETE",
      headers: { authorization: `Bearer ${apiKey}` },
    });

    // 404 means the CRM has no such contact, so the work is done.
    if (!response.ok && response.status !== 404) {
      throw new Error(`The CRM answered ${response.status}`);
    }
  },
});
```

`hooks.onSubscriberDeleted` must be `true`. Without it, your function is never called.

## What you get

```json
{ "subscriber_id": 12, "email": "ada@example.com" }
```

## Common mistakes

**You try to read the subscriber.** The person is gone, so `ctx.broadcast.subscribers.get` fails with `not_found`, and `ctx.store.forSubscriber(id)` fails too. Work only from the two fields you get, and from your shared store. [Build a Referral Program](https://sendbroadcast.net/docs/plugins-build-a-referral-program) shows this.

**You fail on "not found".** If the service has no such contact, the job is done. Do not throw. A throw makes Broadcast try again, up to 5 times.

**You forget the purge.** **Purge All Subscribers** removes everyone at once, and it does not call this hook. Broadcast sends the event `subscribers.purged` instead, and data in `forSubscriber` is still deleted. If you keep data elsewhere, also listen for that event in the [events hook](https://sendbroadcast.net/docs/plugins-hook-events).

**You log the address.** Never write the email to the log. The log hides email addresses, but other personal data is not hidden.
