Security, Privacy, AI and CSR information for all Piano products now lives in one place. Explore our Compliance Center.
Subscriptions
English French
English French

How to filter for Users based on Custom Field Values via API?

This can be done using the publisher/user/search API endpoint

In order to filter based on custom fields, it is necessary to first add the parameter source=CF, followed by a custom_fields parameter containing the (encoded) criteria used to filter on the relevant custom field(s).

Each item in the custom_fields array requires:

  • field_name - the custom field's ID

  • data_type - the field's configured data type

  • condition - the operator and value(s) to filter on

  • response_time - typically {"type":"CURRENT"}

Supported data types and their condition types

Condition type

Parameters

Works with

EQUAL

equal (or optionsEqual for SINGLE_SELECT_LIST)

TEXT, NUMBER, BOOLEAN, ISO_DATE, SINGLE_SELECT_LIST

LIKE

like

TEXT

MORE

more

NUMBER, ISO_DATE

LESS

less

NUMBER, ISO_DATE

BETWEEN

more, less

NUMBER, ISO_DATE

IN

optionsIn (array of {"value":"..."})

MULTI_SELECT_LIST

EMPTY

-

TEXT, NUMBER, ISO_DATE, SINGLE_SELECT_LIST, MULTI_SELECT_LIST

ANY

-

TEXT, NUMBER, BOOLEAN, ISO_DATE, SINGLE_SELECT_LIST, MULTI_SELECT_LIST

NOT EQUAL is not supported as a condition type. To exclude a value, run two separate queries (e.g., one for EMPTY and one for EQUAL":"false") and reconcile the results outside the API.

Examples by field type

Boolean (Checkbox)

JSON
[{"field_name":"custom_field","data_type":"BOOLEAN","condition":{"type":"EQUAL","equal":"true"},"response_time":{"type":"CURRENT"}}]

Number

JSON
[{"field_name":"mobile","data_type":"NUMBER","condition":{"type":"EQUAL","equal":"0503027844"},"response_time":{"type":"CURRENT"}}]

Text

JSON
[{"field_name":"comments","data_type":"TEXT","condition":{"type":"LIKE","like":"refund"},"response_time":{"type":"CURRENT"}}]

Date (ISO_DATE)

JSON
[{"field_name":"birthdate","data_type":"ISO_DATE","condition":{"type":"BETWEEN","more":"1980-02-02","less":"2011-02-01"},"response_time":{"type":"CURRENT"}}]

Single-select list

JSON
[{"field_name":"occupation_status","data_type":"SINGLE_SELECT_LIST","condition":{"type":"EQUAL","optionsEqual":{"value":"Full-time"}},"response_time":{"type":"CURRENT"}}]

Multi-select list

JSON
[{"field_name":"interests","data_type":"MULTI_SELECT_LIST","condition":{"type":"IN","optionsIn":[{"value":"Antilles"},{"value":"Antigua and Barbuda"}]},"response_time":{"type":"CURRENT"}}]

Filtering for empty or any value

  • ANY returns all users who have a value set for that field (regardless of what it is). Works with every data type, including Boolean.

  • EMPTY returns users who were presented with the field but left it blank. It does not match users who never saw the field at all.

JSON
[{"field_name":"account_status","data_type":"TEXT","condition":{"type":"EMPTY"},"response_time":{"type":"CURRENT"}}]

Important - "Empty" vs. "NULL": A field can be blank in two different ways:

  • Empty: the user saw the field on a form and submitted it without a value.

  • NULL: the user never encountered the field at all - for example, the field was created after the user registered, or the user was created via API/import without that field being sent.

The EMPTY condition (both in Mine Users and via this API) only returns the first group. There is currently no operator to search directly for NULL values. To identify users with NULL custom field data:

  1. Run an ANY search to see how many users do have a value.

  2. Compare against your total user count - the difference are users with NULL values.

  3. Alternatively, generate a Users Export and filter for blank values in the file. This bypasses the search index and reads directly from the primary database.

Combining multiple conditions

You can pass several objects in the custom_fields array to filter on more than one custom field at once. All conditions are combined with AND logic; a user must match every condition to be returned.

 {"field_name":"birthday","data_type":"NUMBER","condition":{"type":"ANY"},"response_time":{"type":"MORE","more":"2020-10-28"}},

 {"field_name":"age","data_type":"NUMBER","condition":{"type":"ANY"},"response_time":{"type":"EQUAL","equal":"2020-10-28"}}

Custom field conditions cannot be combined with system field conditions (e.g., subscription status, payment method) in the same request; run separate queries for each.

Sample curl request

curl --location --request POST 'https://sandbox.piano.io/api/v3/publisher/user/search?api_token=TOKEN_VALUE' \\
--header 'Content-Type: application/x-www-form-urlencoded' \\
--data-urlencode 'aid=vwpqa2omsu' \\
--data-urlencode 'exclude_cf_metadata=true' \\
--data-urlencode 'source=CF' \\
--data-urlencode 'custom_fields=[{"field_name": "mobile","data_type": "NUMBER","condition": {"type": "EQUAL","equal": "0503027844"},"response_time": {"type": "CURRENT"}}]'

Once the API call is executed, it will return the matching user registries.

Good to know

  • Results are limited to a maximum of 10,000 users per query (offset + limit ≤ 10000). For larger populations, use the asynchronous /publisher/export/create/userExport endpoint instead.

  • Custom field data can take a few seconds up to a few hours to sync to the search index (up to a minute on Sandbox), so recently updated values may briefly not appear in results.

Last updated: