---
title: "Build a driver comparison page with stable club IDs"
description: "Save the drivers a user picks by clb_ id, fetch them by id, compare variants instead of lofts_deg and hands, and keep a saved club that returns 404."
summary: "GolfAPI.dev club comparisons. List candidates with GET https://api.golfapi.dev/drivers?fields=id,name,manufacturer,lofts_deg,hands. Save each selected record's id (clb_) and fetch it later with GET https://api.golfapi.dev/drivers/{id}, which never redirects. Compare variants[] (hand, loft_deg, market): lofts_deg and hands are unions across variants, so a loft can exist in one hand only. Test-key and live-key ids differ. A saved id that returns 404 not_found stays in the comparison, marked unavailable. Auth: Bearer API key. An absent field is Not published."
url: "https://golfapi.dev/blog/compare-clubs/"
published: "2026-10-16"
updated: "2026-11-12"
tags: ["Drivers","How-to"]
---

# Build a driver comparison page with stable club IDs

If you build a club comparison, save each club's `id` and compare its variants. Names and slugs can change, and `lofts_deg` and `hands` don't tell you which loft comes in which hand. The responses below come from a test key, which reads a fixed sample of drivers.

## List drivers for the user to choose from

Ask the drivers list for the fields a picker shows. `id` is always returned:

```sh
curl 'https://api.golfapi.dev/drivers?fields=id,name,manufacturer,lofts_deg,hands&limit=4' \
  -H "Authorization: Bearer $GOLFDEV_API_KEY"
```

Response with a test key on 3 November 2026. The three Srixon records have no published lofts or hands yet, so a picker shows those columns as Not published:

```json
{
  "data": [
    {
      "id": "clb_01M5CT01FAVETRE90QN4TMTKQG",
      "name": "ZXi RKT LS Driver",
      "manufacturer": { "slug": "srixon", "name": "Srixon" }
    },
    {
      "id": "clb_01M5CT01FAK1D58Y0453W8332H",
      "name": "ZXi RKT Max Driver",
      "manufacturer": { "slug": "srixon", "name": "Srixon" }
    },
    {
      "id": "clb_01M5CT01F9R5SE2Q3ADS9TZBR1",
      "name": "ZXi RKT Driver",
      "manufacturer": { "slug": "srixon", "name": "Srixon" }
    },
    {
      "id": "clb_01M5CT01EDR83NWM5TFT9DZRXF",
      "name": "JPX ONE SELECT Driver",
      "manufacturer": { "slug": "mizuno", "name": "Mizuno" },
      "lofts_deg": [9, 10.5],
      "hands": ["rh", "lh"]
    }
  ],
  "page": { "limit": 4, "has_more": true, "catalog_complete": false, "next": "cur_eyJ5IjoyMDI2…" }
}
```

Do not build an identifier from the name the user types.

## Save the driver id

When the user adds a driver to a comparison, store its `id` (`clb_…`). The `id` never changes. The `slug` can change when a name is corrected, and two drivers can have similar names. The test sample and the live catalog use different ids, so pick clubs again after you switch to a live key.

Fetch a saved driver by `id`; that request never redirects:

```sh
curl 'https://api.golfapi.dev/drivers/clb_01M21M6KHQSKX3MQ0SA1HYNGSZ?fields=id,slug,name,lofts_deg,hands,adjustable_hosel' \
  -H "Authorization: Bearer $GOLFDEV_API_KEY"
```

```json
{
  "id": "clb_01M21M6KHQSKX3MQ0SA1HYNGSZ",
  "slug": "gt1-driver",
  "name": "GT1 Driver",
  "lofts_deg": [9, 10, 12],
  "hands": ["rh", "lh"],
  "adjustable_hosel": true
}
```

## Compare driver variants

`lofts_deg` and `hands` are summaries across a driver's variants. Combining them can describe a club that is not sold. The Qi4D Driver lists lofts 8, 9, 10.5 and 12 and hands `rh` and `lh`, but its variants show that the 8° head is right-handed only:

```sh
curl 'https://api.golfapi.dev/drivers/clb_01M21M6ZEF7DKNPK28F4ZC79ZX?fields=id,name,variants' \
  -H "Authorization: Bearer $GOLFDEV_API_KEY"
```

```json
{
  "id": "clb_01M21M6ZEF7DKNPK28F4ZC79ZX",
  "name": "Qi4D Driver",
  "variants": [
    { "id": "var_01M21M6ZM5RB7JDJ0BV3FHYBQR", "hand": "rh", "market": "US", "loft_deg": 8 },
    { "id": "var_01M21M6ZMPMYWZJEYAJ3QWTJMA", "hand": "rh", "market": "US", "loft_deg": 9 },
    { "id": "var_01M21M6ZN7CPK9BV39FN55DDEQ", "hand": "rh", "market": "US", "loft_deg": 10.5 },
    { "id": "var_01M21M6ZNQS6ZFECM34TNT3K16", "hand": "rh", "market": "US", "loft_deg": 12 },
    { "id": "var_01M21M6ZRZFD7AM155NDDCHHSZ", "hand": "lh", "market": "US", "loft_deg": 9 },
    { "id": "var_01M21M6ZSF1FVVBQ6ZEY37H9EC", "hand": "lh", "market": "US", "loft_deg": 10.5 },
    { "id": "var_01M21M6ZT056BX9AHVQXFF5R9W", "hand": "lh", "market": "US", "loft_deg": 12 }
  ]
}
```

Three drivers from the sample, compared by variant:

| Driver | Right-handed lofts | Left-handed lofts |
| --- | --- | --- |
| Qi4D Driver | 8, 9, 10.5, 12 | 9, 10.5, 12 |
| GT1 Driver | 9, 10, 12 | 9, 10, 12 |
| G440 Max Driver | 9, 10.5, 12 | 9, 10.5, 12 |

A driver variant identifies one `hand`, `loft_deg` and `market`. When a comparison needs a specific head, store the variant `id` (`var_…`) as well as the driver `id`.

A coding agent connected to the [MCP server](https://golfapi.dev/mcp) can read the same records while it builds the page. Ask it to "Read the Qi4D Driver and the GT1 Driver and list the lofts each sells in each hand", and it calls `get_club` once per driver. A Free account's test key answers it, because the sample holds every 2025 and 2026 driver.

## Show a missing value as Not published

A field with no published value is absent from the record; show the cell as Not published and keep real `false` and `0` values. [Handle missing specifications](https://golfapi.dev/blog/missing-specifications/) covers the three states in code.

## Keep a saved driver that no longer resolves

A request for a record the catalog does not carry answers `404`:

```sh
curl 'https://api.golfapi.dev/drivers/not-a-driver' \
  -H "Authorization: Bearer $GOLFDEV_API_KEY"
```

```json
{
  "error": {
    "type": "not_found",
    "message": "No driver with slug 'not-a-driver'. GET /coverage names every manufacturer and model year the published build carries, and reports `catalog_complete: false`. It counts published records, so it cannot tell a head that was never released from one not yet published.",
    "status": 404,
    "request_id": "req_01M6H0TFG8B8QT6Q58HAJPB7PA"
  }
}
```

If a saved `id` starts answering `404`, keep it in the user's comparison and mark it unavailable. Do not replace it with a driver that has a similar name. [GET /changes](https://golfapi.dev/blog/sync-with-changes/) lists saved ids that changed or were removed.
