# Targeting and A/B tests

Send visitors of one Clikso short link to different pages by country or device, or split traffic between pages, using the API.

> **In short:**
>
> One short link can send people to different pages. `geo_targeting` picks a page by country, `device_targeting` by phone or computer, and `ab_testing` splits visitors between pages at random. These need the Pro plan or higher.

## You need

* **API key:** A key with **Write** permission.
* **Role:** Editor or admin in the key’s workspace.
* **Plan:** **Pro** or **Business**. On a lower plan you get `402 UPGRADE_REQUIRED`. See [pricing](https://clik.so/pricing).

## Send visitors by country

`geo_targeting` maps a country code to a URL. Use two-letter ISO country codes in capitals, like `US`, `GB` or `IN`.

```bash
curl -X PUT "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "geo_targeting": {
      "US": "https://example.com/us/summer-sale",
      "IN": "https://example.com/in/summer-sale"
    }
  }'
```

Visitors from those countries go to their page. Everyone else goes to `destination_url`.

Write the codes in capitals. The edge compares them with the visitor’s country in capitals, so `us` never matches.

## Send visitors by device

`device_targeting` takes up to three URLs: `ios`, `android` and `desktop`.

```bash
curl -X PUT "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "device_targeting": {
      "ios": "https://apps.apple.com/app/id000000000",
      "android": "https://play.google.com/store/apps/details?id=com.example.app",
      "desktop": "https://example.com/app"
    }
  }'
```

This is how one link can open the right app store on each phone.

The API also accepts `macos` and `linux` keys, but they have no effect. Only `ios`, `android` and `desktop` change where a visitor goes.

## Split traffic between pages

`ab_testing` is a list of pages, each with a `percentage`. Every visit picks one page at random, weighted by those numbers.

```bash
curl -X PUT "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ab_testing": [
      {
        "url": "https://example.com/summer-sale-a",
        "percentage": 50
      },
      {
        "url": "https://example.com/summer-sale-b",
        "percentage": 50
      }
    ]
  }'
```

Each `percentage` is a whole number from 0 to 100. How the split works:

* The numbers are weights. They do not have to add up to 100. Weights of 1 and 3 send a quarter of visits to the first page.
* `destination_url` is not part of the split. To keep it in the test, add it as one of the pages.
* If every weight is 0, nobody is split, and visitors go to `destination_url`.

## How the rules work together

Clikso checks the rules in this order on every visit:

1. **Country.** If the visitor’s country has a URL, that is the pick so far.
2. **Device.** If a device rule matches, it replaces the country pick.
3. **A/B split.** This runs only when neither a country nor a device rule matched.

If nothing matches, the visitor goes to `destination_url`.

## Remove the rules

To turn a rule off, send it as `null`: `geo_targeting: null`, `device_targeting: null` or `ab_testing: null`.

```bash
curl -X PUT "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "geo_targeting": null,
    "ab_testing": null
  }'
```

Sending it empty works too: `{}`, or `[]` for `ab_testing`. A field you leave out keeps its rules. Clearing a rule always works, on any plan.

## What you get back

A `200` with the whole link in `data`. The rules come back in the same shape you sent:

* `geo_targeting` — the country map, or `null` if never set.
* `device_targeting` — the device map, or `null` if never set.
* `ab_testing` — the list of pages. It is `[]` when there is no split, never `null`.

## Common errors

| Status | Code                  | What it means                                                                                                         | What to do                                                                                               |
| ------ | --------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| 402    | `UPGRADE_REQUIRED`    | The workspace is below Pro. `details.field` names the rule, and `details.required_plan` is `pro`.                     | Leave the field out, or upgrade the workspace.                                                           |
| 403    | `FORBIDDEN`           | The key has only Read permission, or its owner is a viewer.                                                           | Check the key’s permission and your role. If you send `Workspace-Id`, it must match the key’s workspace. |
| 422    | `VALIDATION_ERROR`    | A country code is not two letters, a `percentage` is not a whole number from 0 to 100, or a rule has the wrong shape. | Fix the field and send the request again.                                                                |
| 422    | `DESTINATION_BLOCKED` | One of the target URLs points at another link shortener or a blocked site.                                            | Show `error.message` to the user as it is. Do not retry.                                                 |

## Good to know

* Country comes from the visitor’s IP address. A VPN or a company network can make someone look like they are elsewhere.
* Targeting is by country only. There are no city or region rules.
* "Desktop" means any browser that does not say it is a phone or Android.
* There are no sticky sessions. A visitor who comes back can land on a different A/B page.
* There is no results view per A/B page. Compare pages with the `destinations` breakdown in [click analytics](https://clik.so/docs/guides/analytics).
* Every URL in the rules is checked, just like `destination_url`.
* If a workspace drops below Pro, its links keep their rules. You can still edit other fields, or clear the rules.

---

Source: https://clik.so/docs/guides/targeting
