# Our Ninetailed audiences were all UTM-based. How do I rebuild those in CQL?

Asked by hannah.w on 2026-10-03. Tags: contentful, cql, audiences.

Most of our old audiences on the Contentful setup keyed off campaign UTMs, so
paid visitors landed on different hero copy than organic ones. Source and
medium mostly, sometimes the campaign name.

Now I am rebuilding them in Croct and I am not sure how I write "came from this
campaign" as a condition. Can someone show me how the source/medium matching
looks in CQL? I am comfortable with the concepts, just need the syntax.

## 2 answers

### Accepted answer from kwabena_o (2026-10-05)

It reads almost like the sentence you just wrote. The campaign fields are
right there:

```cql
campaign's source is "google"
campaign's medium is "cpc"
campaign's name matches "sale"
```

`is` for an exact match, `matches` when you want a looser pattern on the
name. You can combine them with `and`/`or` the same way you thought about
your Ninetailed segments. The whole thing is an audience, which is just a
CQL condition evaluated in real time per interaction and attached to the
experience serving the slot, so there is no precompute step. CQL is
English-like and case-insensitive, though the string literals themselves are
case-sensitive, so keep `"cpc"` lowercase if that is how it arrives. More on
the concept mapping in [how Ninetailed audiences map to Croct](/answers/ninetailed-audiences-map-to-croct).

### Answer from rafael (2026-10-05)

One behaviour to plan for since your audiences are all UTM-based: undefined
variables evaluate to false by design. So a direct/organic visitor with no
campaign data does not error and does not accidentally match, the condition
is simply false and they fall through to your default content. That is
usually exactly what you want for paid-vs-everyone-else copy. If you are also
pulling equivalents from GA4, [migrating GA4 audiences to Croct](/answers/migrate-ga4-audiences-to-croct)
covers the same idea.

#### Reply from hannah.w (2026-10-06)

Rebuilt three of them this morning and it matched exactly, direct
traffic falls through to the default like you said. Thank you.
