# Customizing destinations - Docs

Although we recommend using one of our pre-built destinations, you can also customize them and build your own.

## Customizing payload

You can template destination output using curly braces `{}`.

For example, given this PostHog event:

TypeScript

PostHog AI

```typescript
{
    event: {
        event: "$pageview",
        distinct_id: "1234",
        timestamp: "2024-01-01T12:00:00",
        properties: {
            $current_url: "https://posthog.com"
        }
    },
    person: {
        name: "max@posthog.com",
        properties: {
            email: "max@posthog.com",
            first_name: "Max",
            last_name: "the Hedgehog"
        }
    }
}
```

You can create a template like:

PostHog AI

```
{event.event} was triggered by {person.properties.first_name} {person.properties.last_name}
// Outputs: $pageview was triggered by Max the Hedgehog
```

You could use this approach to set parameters in a [webhook](/docs/cdp/destinations/webhook.md) destination’s URL:

PostHog AI

```
https://api.yourgreatwebsite/v0/track-conversion?username={person.name}
```

Or to construct a custom JSON payload that conforms to an existing API specification:

TypeScript

PostHog AI

```typescript
{
    "event_source": "posthog",
    "event": {
        "event_label": "conversion",
        "username": "{person.name}",
        "datetime": "{event.timestamp}"
    }
}
```

> You can see the full capabilities of templating with our Hog programming language in the [Hog documentation](/docs/hog.md)

### Global object

Below is the structure of the global variables available whenever templating a destination.

TypeScript

PostHog AI

```typescript
{
    event: {
        uuid: string // The unique ID of the event
        event: string // The event name (e.g. $pageview)
        distinct_id: string // The distinct_id of the identity that created the event
        properties: Record<string, any>
        timestamp: string
        url: string // A URL to view it in PostHog
    }
    person?: {
        id: string // The UUID of the Person associated with the distinct_id of the event
        name: string // Configured based on your "Display name" property in PostHog
        url: string  // A URL to view it in PostHog
        properties: Record<string, any>
    }
    groups?: {
        [id: string]: {
            id: string
            type: string
            index: number
            url: string  // A URL to view it in PostHog
            properties: Record<string, any>
        }
    }
    project: {
        id: number  // The ID of the PostHog project
        name: string  // The name of the PostHog project
        url: string  // A URL to view it in PostHog
    }
    source?: {
        name: string // The name of the source (typically the destination name)
        url: string  // A URL to view it in PostHog
    }
}
```

### Adding session replay links to Slack messages

You can enhance your Slack notifications by adding direct links to session recordings. This is particularly useful when you want to quickly investigate the context of an event by watching the session replay.

For example, to add a "Replay" button to your Slack message, you can add this block to your Slack destination's payload:

JSON

PostHog AI

```json
{
    "url": "{project.url}/replay/{event.properties.$session_id}?t={event.timestamp}",
    "text": {
        "text": "Replay",
        "type": "plain_text"
    },
    "type": "button"
}
```

This creates a button in your Slack message that links directly to the session recording at the exact timestamp when the event occurred. The URL is constructed using:

-   `{project.url}` - The base URL of your PostHog instance
-   `{event.properties.$session_id}` - The session ID from the event
-   `{event.timestamp}` - The timestamp when the event occurred

For this to work the event must have the `session_id` as property on the event as well as a session recording associated with the `session_id`.

## Modifying destinations with Hog

For most cases, we recommend using one of the templates. These take care of most logic under the hood, exposing simple inputs for you to configure.

You can, however, modify any destination by clicking `show source code`. From here you can modify the inputs – for example marking an input as secret so that it is encrypted as rest – or changing the implementation of the destination itself.

Destinations are written in our [Hog language](/docs/hog.md). Most destinations are wrappers around `fetch` - a function for safely performing async, retry-able HTTP calls.

Hog

PostHog AI

```rust
let res := fetch(inputs.url, {
  'headers': inputs.headers,
  'body': inputs.body,
  'method': inputs.method
});
if (res.status >= 400) {
  print('Bad response', res.status, res.body)
}
```

For more details and inspiration, you can always view the source code of any destination.

### Guidelines for modifying a destination

-   **Start from an existing template:** Check out existing templates that are close to the problem you’re solving and work from there.

-   **Rely on filters:** Offload as much as possible to the built in `filters` and `inputs`. This will make modifying your destination later much simpler (as well as being more performant).

-   **Use `inputs` wherever possible:** These are great for things like API credentials. You can even mark them as secret: they will not be returned to the UI in the future and will be stored encrypted.

-   **Keep it short:** We have tight controls on execution time, memory usage.

-   **Do not perform more than 5 `fetch` calls:** The function will error if you do. If you need to do more than 5 calls, please [contact support](https://us.posthog.com/#panel=support%3Asupport%3Aapps%3A%3Atrue).

### Community questions

Ask a question

### Was this page useful?

HelpfulCould be better