Appearance
Destinations
Destinations are the buttons on a smart link — Spotify, Apple Music, a merch store, a ticket page. They live in the link_destinations table and are created automatically by Create Link, but you can add, edit, reorder, and remove them yourself.
Reading destinations
Usually you want them nested under their link:
graphql
query LinkWithDestinations($id: uuid!) {
links_by_pk(id: $id) {
id
path
destinations(order_by: { priority: asc }) {
id
type
url
cta
text
logo
enabled
priority
deeplink_ios
deeplink_android
clickthroughs_total
}
}
}Or query the table directly when you need to filter across links:
graphql
query DisabledDestinations($artist_id: uuid!) {
link_destinations(
where: {
link: { artist_id: { _eq: $artist_id } }
enabled: { _eq: false }
}
) {
id
type
link { id path }
}
}Fields
| Field | Type | Description |
|---|---|---|
id | uuid! | Destination ID. Referenced by link_statistics.destinations. |
link_id | uuid | Owning link. |
type | String | Service identifier — see below. |
url | String | Where the button sends the visitor. |
cta | String | Button label. |
text | String | Secondary label used in some layouts. |
description | String | Optional supporting copy. |
logo | String | Icon URL. Auto-derived from the destination domain on creation. |
enabled | Boolean | Whether the button renders. |
priority | Int | Display order, ascending. |
deeplink_ios | String | iOS app deeplink. |
deeplink_android | String | Android app deeplink. |
pre_release | Boolean | Show only before the link's release_time. |
is_background_image | Boolean | Render this destination's art as the page background. |
parent_id | uuid | Parent destination, for grouped buttons. |
associated_link_id | uuid | Another ArtistHub link this destination points at. |
autoplay_track | String | Track autoplayed when this destination is previewed. |
config | jsonb | Service-specific settings. |
rid | String | Internal release identifier. |
short_id | String | Short identifier used in tracking URLs. |
clickthroughs_total | Int | Lifetime clicks on this button. |
Destination types
spotify, applemusic, amazonmusic, deezer, itunes, youtube, soundcloud, tidal, pandora, custom.
Use custom for anything that is not a streaming service — merch, tickets, a Discord invite, a TikTok sound page. create_link uses custom for the TikTok "Use My Sound" destination it generates.
Adding a destination
graphql
mutation AddDestination($destination: link_destinations_insert_input!) {
insert_link_destinations_one(object: $destination) {
id
type
url
cta
priority
}
}Variables:
json
{
"destination": {
"link_id": "9c4b2f10-...",
"type": "custom",
"url": "https://store.example.com/vinyl",
"cta": "Buy the Vinyl",
"text": "Buy the Vinyl",
"enabled": true,
"priority": 10
}
}Insertable columns: link_id, artist_id, type, url, cta, text, description, logo, enabled, priority, deeplink_ios, deeplink_android, pre_release, is_background_image, icon_type, parent_id, associated_link_id, autoplay_track, config, rid.
The link_id must belong to an artist you manage, or the insert is rejected.
Adding several at once
graphql
mutation AddMany($objects: [link_destinations_insert_input!]!) {
insert_link_destinations(objects: $objects) {
affected_rows
returning { id type url priority }
}
}Editing a destination
graphql
mutation EditDestination($id: uuid!, $changes: link_destinations_set_input!) {
update_link_destinations_by_pk(pk_columns: { id: $id }, _set: $changes) {
id
cta
url
enabled
priority
}
}Updatable columns: url, cta, text, description, logo, enabled, priority, deeplink_ios, deeplink_android, pre_release, is_background_image, type, link_id, parent_id, associated_link_id, autoplay_track, config, rid.
clickthroughs_total and short_id are server-managed and cannot be set.
Reordering
priority controls display order, ascending. Reorder by writing new values:
graphql
mutation Reorder {
spotify: update_link_destinations_by_pk(
pk_columns: { id: "b2d1..." }
_set: { priority: 1 }
) { id priority }
apple: update_link_destinations_by_pk(
pk_columns: { id: "c8e4..." }
_set: { priority: 2 }
) { id priority }
}GraphQL executes top-level mutation fields in order, so aliasing several updates into one document is a safe way to apply a whole reorder atomically from the client's point of view.
Leave gaps — 10, 20, 30 rather than 1, 2, 3 — so a later insert does not require renumbering.
Hiding instead of deleting
Disabling keeps the click history and lets you restore the button later:
graphql
mutation Disable($id: uuid!) {
update_link_destinations_by_pk(
pk_columns: { id: $id }
_set: { enabled: false }
) {
id
enabled
}
}Deleting
graphql
mutation DeleteDestination($id: uuid!) {
delete_link_destinations_by_pk(id: $id) { id type }
}Deleting orphans the destination's rows in analytics — link_statistics.destinations reports by destination_id, and a deleted ID no longer resolves to a name. Prefer enabled: false for anything you may want to report on.
Pre-release destinations
pre_release: true shows a destination only before the link's release_time, which is how a presave button gives way to streaming buttons on release day.
graphql
mutation {
insert_link_destinations_one(object: {
link_id: "9c4b2f10-..."
type: "spotify"
url: "https://open.spotify.com/album/4uLU6hMCjMI75M1A2tKUQC"
cta: "Pre-save on Spotify"
pre_release: true
enabled: true
priority: 1
}) {
id
pre_release
}
}Filling missing deeplinks
When a link is created before every DSP has the release live, some destinations are missing or lack app deeplinks. fill_missing_deeplinks re-runs the resolution pass:
graphql
mutation FillDeeplinks($link_id: String!) {
fill_missing_deeplinks(link_id: $link_id) {
success
}
}Run it after release day on any pre-release link. Existing destinations are left alone; only missing ones are added.
Find candidates with:
graphql
query NeedsFilling($artist_id: uuid!) {
links(
where: {
artist_id: { _eq: $artist_id }
type: { _eq: "release" }
_not: { destinations: { type: { _eq: "applemusic" } } }
}
) {
id
path
title
}
}