# Best practices

These habits get you better matches from the API and a smoother experience for your users.

## Always include duration

The `duration` parameter makes a big difference to matching. It helps tell apart:

-   Radio edits vs album versions
-   Live vs studio recordings
-   Different songs with similar names

```bash
# Good - includes duration
/getLyrics?s=Bohemian%20Rhapsody&a=Queen&al=A%20Night%20at%20the%20Opera&d=354

# Less accurate - missing duration
/getLyrics?s=Bohemian%20Rhapsody&a=Queen&al=A%20Night%20at%20the%20Opera
```

Always include it, together with the album. The cache key includes both, so a request without them often misses the cached entry and, without an API key, returns `401`.

## Always include the album name

Including the album name helps the API find the correct version of a song, especially when:

-   The song appears on multiple albums
-   There are remastered or deluxe editions
-   The artist has re-recorded songs

```bash
# Recommended - includes album
/getLyrics?s=Yesterday&a=The%20Beatles&al=Help!&d=125

# Less specific - may return wrong version
/getLyrics?s=Yesterday&a=The%20Beatles&d=125
```

The API accepts a request without an album, but the cache key includes it, so a request without it often misses the cached entry and, without an API key, returns `401`. Always send it.

## Trim whitespace from input

The API normalizes input on the server, but trimming leading and trailing whitespace before you send can still improve cache hit rates:

```javascript
// Before
song = "  E85  "

// After
song = song.trim() // "E85"
```

## Implement client-side caching

Reduce API calls by caching responses locally:

```javascript
const lyricsCache = new Map();

async function getLyrics(song, artist, album, duration) {
  const key = `${song.toLowerCase()}|${artist.toLowerCase()}|${album.toLowerCase()}|${duration}`;

  if (lyricsCache.has(key)) {
    return lyricsCache.get(key);
  }

  const result = await fetchFromAPI(song, artist, album, duration);
  lyricsCache.set(key, result);

  return result;
}
```

To keep it across sessions, persist the cache to localStorage or IndexedDB.

## Handle negative cache hits

When you receive `X-Cache-Status: NEGATIVE_HIT`, the API previously searched for this song and found no lyrics. Don't retry immediately.

-   Store negative results locally to avoid repeat requests
-   Show a "lyrics not available" message to users
-   If you know lyrics should exist, use `/revalidate` (requires API key)

## Respect rate limits

For production applications:

-   Play uncached songs through the [Better Lyrics](https://better-lyrics.boidu.dev/) extension first to populate the cache
-   Queue requests to avoid bursts
-   Add delays between batch requests
-   Back off when you get a 429

## Pre-fetch upcoming songs

If you know which songs play next, fetch their lyrics early:

-   Fetch lyrics when a playlist loads, not when each song starts
-   Limit concurrent requests to avoid rate limiting
-   Prioritize songs near the current playback position

```javascript
// Pre-fetch next 3 songs in playlist
async function prefetchPlaylist(playlist, currentIndex) {
  const toFetch = playlist.slice(currentIndex, currentIndex + 3);

  for (const track of toFetch) {
    // Stagger requests to avoid bursts
    await fetchLyrics(track.song, track.artist, track.album, track.duration);
    await sleep(200);
  }
}
```

## Parse TTML efficiently

TTML parsing can be expensive. A few ways to keep it cheap:

-   Parse once and cache the structured result
-   Use a Web Worker for parsing if it blocks the main thread
-   Pre-compute the next few lines during playback
-   Use [`@braccato/parsers`](https://docs.betterlyrics.org/braccato/parsers) (built from the Better Lyrics parsers) instead of writing your own

## Handle missing timing

Timing data can be incomplete in some documents:

-   Check that `begin` and `end` attributes exist
-   Validate that times are parseable
-   Fall back to line-level display if syllable timing is missing

## Test with edge cases

Test your integration with:

-   Songs with special characters in names
-   Very long songs (10+ minutes)
-   RTL languages (Arabic, Hebrew)
-   Songs with no lyrics available
-   Songs with instrumental sections

## Monitor your usage

Track these to see how your integration behaves:

-   Cache hit rate (from `X-Cache-Status` header)
-   Error rate by status code
-   Response times
-   Rate limit encounters

## Attribute Better Lyrics

If your project uses this API, consider adding a link to [Better Lyrics](https://better-lyrics.boidu.dev/) in your app or README. It helps other people find the project and keeps development going.

Source: https://docs.betterlyrics.org/docs/best-practices
