---
title: "The song_link (lis.tn) universal music link"
description: "Every AudD match includes a song_link on the lis.tn domain; how its ?thumb and ?provider conventions and the SDK helpers let you build cover-art and 'open in your service' UIs without requesting provider metadata."
slug: "/resources/concepts/lisn-song-link"
section: "concepts"
keywords: [audd, song_link, lis.tn, cover art, streaming links, thumbnail]
---

# The song_link (lis.tn) universal music link

Every AudD match comes back with a `song_link` — a universal URL on the
`lis.tn` domain that resolves to a page linking the recognized song across
streaming services. It's present on a match whether or not you ask for any
provider metadata, which makes it the cheapest way to put a clickable result
and its cover art in front of a user. This page covers what `song_link` is,
the two URL conventions it supports, and when to reach for it versus
requesting full provider blocks.

## TL;DR

- Every match includes `song_link`, e.g. `https://lis.tn/Warriors`. No
  provider metadata request needed — it's there by default.
- On a `lis.tn`-hosted link, two conventions work:
  - append `?thumb` → the cover-art image URL
    (`https://lis.tn/Warriors?thumb`).
  - append `?<provider>` → a redirect to that provider
    (`https://lis.tn/Warriors?spotify`, `…?apple_music`).
- The SDKs wrap these: `thumbnail_url` / `thumbnailUrl` for cover art,
  `streaming_url(provider)` / `streamingUrl(provider)` for a provider
  redirect.
- These conventions apply **only** to `lis.tn`-hosted links. Some
  `song_link`s point elsewhere (e.g. a YouTube URL) and won't support
  `?thumb` / `?<provider>`; the SDK helpers return `null` in that case.
- Want structured metadata and direct provider URLs instead of redirects?
  Request provider blocks with `return` — at the cost of a little latency.

## Why this matters

The common UI need after a recognition — show the cover art, give the user a
button to open the track in their music service — has two ways to be solved,
and the cheap one is right more often than people expect.

The expensive way is to request provider metadata blocks (`apple_music`,
`spotify`, …) on every recognition. That gives you structured objects and
direct URLs, but each requested provider adds latency to the call, and you
pay that cost on every recognition even when the user never clicks through.

The cheap way uses only `song_link`, which is already in the response. A
`lis.tn` link is a universal redirect: send the user to it and `lis.tn` sends
them on to a service that has the track; append `?thumb` and it hands you the
cover image. No extra providers requested, no extra latency on the
recognition call. For a "tap to open, here's the artwork" UI, that's usually
all you need.

The guardrail: the `?thumb` and `?<provider>` conventions only work on links
actually hosted on `lis.tn`. A `song_link` can occasionally point somewhere
else, and the conventions won't apply there — which is exactly why the SDK
helpers exist and why they return `null` rather than handing you a broken URL.

## What `song_link` is

`song_link` is a universal music link on the `lis.tn` domain. It resolves to
a landing page for the recognized track that links out to the streaming
services carrying it. It's on every match, without requesting any provider
metadata:

```json
{
  "status": "success",
  "result": {
    "artist": "Imagine Dragons",
    "title": "Warriors",
    "album": "Smoke + Mirrors (Deluxe)",
    "song_link": "https://lis.tn/Warriors"
  }
}
```

A bare recognition call — no `return`, no provider blocks — already gives you
this:

```python
from audd import AudD

audd = AudD("test")  # 10 free standard-endpoint requests/day; your own token at dashboard.audd.io

song = audd.recognize("https://audd.tech/example.mp3")
print(song.song_link)  # -> https://lis.tn/Warriors
```

That single URL is a complete click-through: it works as a link a user can
tap to open the song on a service they already use.

## The `?thumb` convention: cover art

Append `?thumb` to a `lis.tn` `song_link` and it returns the cover-art image
URL for the track:

```
https://lis.tn/Warriors?thumb
```

Use it directly as an `<img>` source. There's no separate artwork request and
no provider block to ask for — the cover art rides along on the link you
already have.

```html
<img src="https://lis.tn/Warriors?thumb" alt="cover art">
```

## The `?<provider>` convention: open in a service

Append `?<provider>` to a `lis.tn` `song_link` and it redirects to that
provider's page for the track:

```
https://lis.tn/Warriors?spotify
https://lis.tn/Warriors?apple_music
```

This is a redirect, not a metadata object: the URL sends the user straight to
the service. It's exactly what you want behind an "Open in Spotify" /
"Open in Apple Music" button — no need to request that provider's block just
to produce the link.

## The SDK helpers

Rather than concatenating query strings by hand, the SDKs expose helpers that
build these URLs for you — and, importantly, return `null` when the
`song_link` isn't a `lis.tn` link that supports the convention:

- Cover art: `thumbnail_url` (Python, snake_case languages) /
  `thumbnailUrl` (Node, Swift, camelCase languages).
- Provider redirect: `streaming_url(provider)` / `streamingUrl(provider)`.

```ts
// Node
const song = await audd.recognize(source);

const cover = song.thumbnailUrl;                 // lis.tn ?thumb URL, or null
const spotify = song.streamingUrl("spotify");    // lis.tn ?spotify redirect, or null
const apple = song.streamingUrl("apple_music");
```

```python
# Python
song = audd.recognize(source)

cover = song.thumbnail_url                 # lis.tn ?thumb URL, or None
spotify = song.streaming_url("spotify")    # lis.tn ?spotify redirect, or None
```

Prefer these helpers over building the URL yourself. They encode the
`lis.tn`-only rule below so you don't ship a broken link.

## When the conventions don't apply

> **`?thumb` and `?<provider>` only work on `lis.tn`-hosted links.** Most
> `song_link`s are on `lis.tn`, but some point elsewhere (for example, a
> YouTube URL). For those, appending `?thumb` or `?spotify` does nothing
> useful — the destination doesn't honor the convention. The SDK helpers
> detect this and return `null` (or `None`) instead of a non-working URL, so
> always treat the helper result as optional and have a fallback.

In practice this means: don't assume `thumbnailUrl` is always a string.
Render the artwork only when it's present, and fall back to a placeholder or
to a provider block (if you requested one) when it's `null`.

## `song_link` vs requesting provider blocks

The `lis.tn` conventions and the `return` provider blocks solve overlapping
problems with different trade-offs.

| | `song_link` conventions | Provider blocks via `return` |
|---|---|---|
| In the response by default | Yes | No — must list providers in `return` |
| Cost | None extra | Each requested provider adds latency |
| What you get | A universal redirect + a cover-art URL | Structured per-provider metadata and direct URLs/IDs |
| Direct vs redirect | Redirect through `lis.tn` | Direct provider URL |
| Works for any provider | Only those `lis.tn` routes to | Only the providers you requested |

Reach for `song_link` + helpers when you need a click-through and cover art
and nothing more — that's the majority of "show the result" UIs, and it
keeps the recognition call fast. Request provider blocks with `return` (e.g.
`return=apple_music,spotify`) when you need structured metadata — provider
track IDs, preview URLs, direct (non-redirect) links — and can absorb the
added latency.

## Worked example

A "now playing" card built entirely from `song_link`, with no provider blocks
requested. The recognition call is minimal and fast; the card still shows
cover art and an "open in your service" button.

```ts
// Node — minimal recognition, no provider metadata requested
const song = await audd.recognize(source);

if (!song) {
  render({ empty: true });
} else {
  render({
    artist: song.artist,
    title: song.title,
    // cover art straight off song_link?thumb (null if not a lis.tn link)
    cover: song.thumbnailUrl,
    // "open in your service" buttons — each is a lis.tn redirect, or null
    links: {
      spotify: song.streamingUrl("spotify"),
      appleMusic: song.streamingUrl("apple_music"),
      deezer: song.streamingUrl("deezer"),
    },
    // the universal fallback link, always present on a match
    songLink: song.songLink,
  });
}
```

The rendering side treats every helper result as optional:

```ts
function render(card) {
  // cover art with a placeholder fallback when thumbnailUrl is null
  const img = card.cover ?? "/placeholder-cover.png";

  // show only the provider buttons that resolved; always show the universal link
  const buttons = Object.entries(card.links)
    .filter(([, url]) => url != null)
    .map(([name, url]) => ({ name, url }));

  // card.songLink is always there as the catch-all click-through
}
```

Because nothing here requested a provider block, the recognition stays fast,
and the card degrades gracefully: if the match's `song_link` isn't a `lis.tn`
link, the provider buttons and cover simply don't render, while `songLink`
itself still gives the user a working click-through.

## Common mistakes

- **Requesting provider blocks just to get cover art or a click-through.**
  `song_link` + `?thumb` already covers that, with no added latency. Save
  `return` for when you genuinely need structured provider metadata.
- **Assuming `thumbnailUrl` / `streamingUrl(...)` is always non-null.** They
  return `null` when the `song_link` isn't a `lis.tn` link that supports the
  convention. Always have a fallback.
- **Hand-building `?thumb` / `?spotify` URLs on a raw `song_link`.** That
  breaks silently on non-`lis.tn` links. Use the SDK helpers, which encode the
  rule and fail safely.
- **Treating `?<provider>` as a metadata source.** It's a redirect to the
  service, not a data object. If you need the provider's track ID or a preview
  URL, request that provider's block with `return`.

---

**Related**

- [Build a now-playing widget](/resources/recipes/now-playing-widget)
- [Build a Shazam-style song identifier](/resources/recipes/shazam-clone)
- [SDK docs](https://docs.audd.io/sdks)
- [API reference](https://docs.audd.io)