---
title: "Save click-test regions"
method: PUT
path: "/surveys/{id}/questions/{questionId}/click-regions"
tags: ["Surveys"]
---

# Save click-test regions

`PUT /surveys/{id}/questions/{questionId}/click-regions`

## Request

- Base URL: `https://api.pickfu.com/v1`
- URL: `https://api.pickfu.com/v1/surveys/{id}/questions/{questionId}/click-regions`
- Auth: HTTP bearer

Saves the whole set of regions for a click-test question's current image as a new revision, and returns it with unfiltered first-click counts. Allowed on draft, live and completed surveys for users who can edit the survey; requires an API key with write permission.

Send the `imagePublicId` and `revision` the GET returned (revision 0 when there is none). Regions are fractions of the image (`x`, `y`, `w`, `h` in 0 to 1), at most 50, with unique keys; they may share an edge but not overlap. Saving regions equal to the current ones creates no revision.

### Errors
- 409 `CLICK_REGIONS_IMAGE_CHANGED`: the question's image was replaced since the GET. Reload and draw the regions again.
- 409 `CLICK_REGIONS_STALE_REVISION`: someone saved since the GET, or a concurrent save won. Reload and reapply.
- Both carry `current: { imagePublicId, revision }`.
- 422 `CLICK_REGIONS_INVALID`: the message names each region to fix (overlap, out of bounds, zero size, duplicate key).

## Path parameters

- `id` string, required
- `questionId` string, required

## Request body

- object
  - `imagePublicId` string, required: The image the regions were drawn on: `imagePublicId` from the GET. A save for any other image is refused with 409 `CLICK_REGIONS_IMAGE_CHANGED`.
  - `revision` integer, required: The revision being edited: `revision` from the GET, 0 when there is none yet. A save against an older revision is refused with 409 `CLICK_REGIONS_STALE_REVISION`.
  - `regions` object[], required: The whole set, replacing the current one. Boxes may share an edge but not overlap, and must lie within the image.
    - `key` string, required: Unique within the set, such as `slot-3`
    - `label` string, nullable: Shown to people reading results; null or omitted for none
    - `x` number, required: Left edge, as a fraction of the image width
    - `y` number, required: Top edge, as a fraction of the image height
    - `w` number, required: Width, as a fraction of the image width; above 0
    - `h` number, required: Height, as a fraction of the image height; above 0

## Response `200`

Default Response

- object
  - `imagePublicId` string: The question's current image
  - `revision` integer: The current revision for that image; 0 when none
  - `regions` object[]: Boxes as fractions of the image from its top left; empty when none
    - `key` string
    - `label` string, nullable
    - `x` number
    - `y` number
    - `w` number
    - `h` number
  - `source` string, nullable: `template` (seeded from a mockup template), `detected` or `drawn`; null when none
  - `counts` object
    - `mode` 'first' | 'all'
    - `respondents` integer: Respondents with at least one click, after filters
    - `clicks` integer: Clicks counted; equals `respondents` in `first` mode
    - `regions` object[]: One tally per region, in stored order
      - `key` string
      - `label` string, nullable
      - `count` integer
      - `share` integer: Whole percent of respondents (`first`) or clicks (`all`); the regions and `outside` sum to 100, or are all 0 with nothing counted
      - `ci95` object, nullable: Wilson 95% interval in percent, one decimal; null in `all` mode or with no respondents
        - `low` number
        - `high` number
    - `outside` object: Clicks outside every region
      - `count` integer
      - `share` integer: Whole percent of respondents (`first`) or clicks (`all`); the regions and `outside` sum to 100, or are all 0 with nothing counted
      - `ci95` object, nullable: Wilson 95% interval in percent, one decimal; null in `all` mode or with no respondents
        - `low` number
        - `high` number
    - `noClearWinner` boolean, nullable: A heuristic, not a significance test: true when the two most-clicked regions' intervals overlap (a tie always does), so no region should be called the winner yet. Null outside `first` mode, with fewer than two regions, or with no respondents.

## Other responses

- `400`: Default Response
- `401`: Default Response
- `403`: Default Response
- `404`: Default Response
- `409`: Default Response
- `422`: Default Response

---

[API](https://skmtc.dev/pickfu/apis/pickfu-api.md) · [All operations](https://skmtc.dev/pickfu/apis/pickfu-api/llms.txt) · [OpenAPI document](https://skmtc.dev/pickfu/apis/pickfu-api/revisions/919fc58413ea?raw)
