---
title: "List widgets"
method: GET
path: "/v1/sites/{site_id}/widgets"
tags: ["Widgets"]
---

# List widgets

`GET /v1/sites/{site_id}/widgets`

## Request

- Base URL: `https://api.getsitecontrol.com`
- URL: `https://api.getsitecontrol.com/v1/sites/{site_id}/widgets`
- Auth: HTTP bearer

Widgets of the site in ascending order of id; `order=newest` gives the latest first. Each one comes with its name, its first headline, layout, whether it is on (`is_active`), its folder, what it can do (`actions`) and has (`features`), your draft of it (`draft`) and where and when it shows (`targeting`). Every feature is also a filter of the same name; filters combine: every one given must match.

Nested lists keep their first 5 entries and texts their first 200 characters (links and `targeting` stay whole); `truncated` names what was cut, Get a widget has it whole.

`total` counts every widget matching the filters, so `limit=1` answers how many there are. `fields` keeps only the named fields of each widget: `fields=id,name,is_active` lists many widgets cheaply.

A page holds up to `limit` widgets; while `next_cursor` is set, pass it as `cursor` for the next page. The content of one widget and the emails its responses go to are in Get a widget.

Deleted widgets are listed only with `is_deleted=true`, for Restore widgets.

## Path parameters

- `site_id` integer, required

## Query parameters

- `is_active` boolean: true: only widgets that are on; false: only off
- `layout` 'modal' | 'bar' | 'panel' | 'slide_in' | 'sidebar' | 'fullscreen' | 'inline': Where the widget sits on the page, named as in the admin. modal: a window centred over the page. bar: a strip across the top or bottom of the page. panel: a box attached to the bottom of the screen, opened from its header. slide_in: a box that slides in from a corner. sidebar: a panel attached to the left or right edge of the screen. fullscreen: covers the whole screen. inline: placed inside the page content. "Pop-up" is not a layout: users call any widget a pop-up.
- `search` string: Words of the name in order (case, spacing and punctuation are ignored), the id, or words of the widget's own text
- `updated_since` string, date-time: Changed at or after this moment; without an offset, taken as UTC; a plain date means its start. A move to another folder is not a change; a deleted widget is listed only with `is_deleted=true`
- `folder_id` integer: Only the items of this folder, an id from `list_folders`; 0 is General
- `is_deleted` boolean: true: only deleted widgets, the trash, for Restore widgets; false: live widgets
- `cursor` string: `next_cursor` of the previous page, sent with the same `order`; omit for the first
- `limit` integer: Items per page
- `fields` string: Comma-separated fields to keep in each item, for example `id,name`; each item then carries only those fields and `id`. Omit for every field
- `order` 'oldest' | 'newest': Order of a list. oldest: the oldest item first; newest: the newest item first, for the latest items without paging through the history.
- `collects_email` boolean: Has an e-mail field. true: only such widgets; false: only the others
- `collects_phone` boolean: Has a phone field. true: only such widgets; false: only the others
- `has_coupon` boolean: A button copies or applies a discount code. true: only such widgets; false: only the others
- `has_game` boolean: Has a game: a wheel, a scratch card or a reveal. true: only such widgets; false: only the others
- `has_countdown` boolean: Has a countdown timer. true: only such widgets; false: only the others
- `has_teaser` boolean: Has a teaser, the small tab shown before or after it. true: only such widgets; false: only the others
- `captcha` boolean: reCAPTCHA checks its form submits. true: only such widgets; false: only the others
- `double_opt_in` boolean: A new subscriber confirms the address by e-mail first. true: only such widgets; false: only the others
- `email_quality_filter` boolean: Submits with disposable or untrusted e-mail addresses are rejected. true: only such widgets; false: only the others
- `notifications` boolean: Responses are e-mailed: switched on, with a recipient. true: only such widgets; false: only the others
- `in_ab_test` boolean: In an A/B test, named in `ab_test_group`. true: only such widgets; false: only the others
- `has_integration` boolean: An integration, webhook or Zapier switched on sends its responses. true: only such widgets; false: only the others
- `has_draft` boolean: You have a draft of it with unsaved changes, see `draft`. true: only such widgets; false: only the others

## Response `200`

Successful Response

- WidgetPage: One page of a list; `next_cursor` is null on the last page.
  - `items` Widget[], required
    - `id` integer, required
    - `name` string, nullable
    - `headline` string, nullable: The widget's first headline, plain text; null when it has none
    - `layout` 'modal' | 'bar' | 'panel' | 'slide_in' | 'sidebar' | 'fullscreen' | 'inline' | 'other', required: Where the widget sits on the page, named as in the admin. modal: a window centred over the page. bar: a strip across the top or bottom of the page. panel: a box attached to the bottom of the screen, opened from its header. slide_in: a box that slides in from a corner. sidebar: a panel attached to the left or right edge of the screen. fullscreen: covers the whole screen. inline: placed inside the page content. other: a layout the admin no longer offers. "Pop-up" is not a layout: users call any widget a pop-up.
    - `is_active` boolean, required
    - `ab_test_group` WidgetAbTestGroup
      - `id` integer, required
      - `name` string, nullable
    - `folder` Folder, required
      - `id` integer, required: 0 is General, where items outside any folder are
      - `name` string, required
    - `actions` string[], required: Event types the widget can produce besides show and close
    - `features` WidgetFeatures, required
      - `collects_email` boolean, required: Has an e-mail field
      - `collects_phone` boolean, required: Has a phone field
      - `has_coupon` boolean, required: A button copies or applies a discount code
      - `has_game` boolean, required: Has a game: a wheel, a scratch card or a reveal
      - `has_countdown` boolean, required: Has a countdown timer
      - `has_teaser` boolean, required: Has a teaser, the small tab shown before or after it
      - `captcha` boolean, required: reCAPTCHA checks its form submits
      - `double_opt_in` boolean, required: A new subscriber confirms the address by e-mail first
      - `email_quality_filter` boolean, required: Submits with disposable or untrusted e-mail addresses are rejected
      - `notifications` boolean, required: Responses are e-mailed: switched on, with a recipient
      - `in_ab_test` boolean, required: In an A/B test, named in `ab_test_group`
      - `has_integration` boolean, required: An integration, webhook or Zapier switched on sends its responses
      - `has_draft` boolean, required: You have a draft of it with unsaved changes, see `draft`
    - `targeting` WidgetTargeting, required
      - `is_complete` boolean, required: False when some rules could not be read into the blocks below
      - `warnings` string[], required: Informational notes; wording is not stable, do not parse
      - `pages` TargetingPages
        - `include` string[], required
        - `exclude` string[], required
      - `audience` TargetingAudience
        - `match` 'all' | 'any', required: all: every item must hold; any: one is enough.
        - `segments` TargetingAudienceSegment[], required
          - `match` 'all' | 'any', required: all: every item must hold; any: one is enough.
          - `conditions` TargetingAudienceCondition[], required
            - `key` string, required
            - `operator` 'is' | 'is_not' | 'less_than' | 'greater_than' | 'starts_with' | 'does_not_start_with' | 'ends_with' | 'does_not_end_with' | 'contains' | 'does_not_contain' | 'matches' | 'does_not_match' | 'has_any_value' | 'is_undefined' | 'matches_url' | 'does_not_match_url' | 'matches_ip' | 'does_not_match_ip' | 'any_of' | 'none_of' | 'during' | 'not_during', required: How a condition tests its value; any_of and none_of take a list, during and not_during a range, has_any_value and is_undefined no value.
            - `value` unknown
            - `subject` string, nullable
      - `start` TargetingStart
        - `mode` 'immediate' | 'programmatically' | 'triggers', required: immediate: on page load; programmatically: only when the site's code shows it; triggers: when one of `triggers` fires.
        - `triggers` TargetingTrigger[], required
          - `type` 'exit_intent' | 'scroll_percent' | 'time_on_page_seconds' | 'time_on_site_seconds' | 'inactivity_seconds' | 'add_to_cart' | 'remove_from_cart' | 'automatic' | 'display_time_seconds', required: What fires a show or a hide; a *_seconds or *_percent trigger carries its threshold in `value`.
          - `value` union
            - integer
            - number
      - `hide` TargetingHide
        - `triggers` TargetingTrigger[], required
          - `type` 'exit_intent' | 'scroll_percent' | 'time_on_page_seconds' | 'time_on_site_seconds' | 'inactivity_seconds' | 'add_to_cart' | 'remove_from_cart' | 'automatic' | 'display_time_seconds', required: What fires a show or a hide; a *_seconds or *_percent trigger carries its threshold in `value`.
          - `value` union
            - integer
            - number
      - `stop` TargetingStop
        - `rules` TargetingStopRule[], required
          - `event` 'action' | 'close' | 'hide' | 'show' | 'show_count', required: The visitor's event after which the widget stops showing; close and show are named for their event. action: after the visitor submits it or clicks its button. hide: after a hide trigger hides it. show_count: after `count` shows.
          - `mode` 'forever' | 'duration': forever: never again after the event; duration: not for `duration_seconds` after it.
          - `duration_seconds` number, nullable
          - `count` integer, nullable
      - `schedule` TargetingSchedule
        - `match` 'all' | 'any', required: all: every item must hold; any: one is enough.
        - `segments` TargetingScheduleSegment[], required
          - `match` 'all' | 'any', required: all: every item must hold; any: one is enough.
          - `conditions` TargetingScheduleCondition[], required
            - `key` 'date' | 'time' | 'weekday', required: date: a range of days; time: a range of hours in a time zone; weekday: days of the week, 0 is Sunday.
            - `operator` 'is' | 'is_not' | 'less_than' | 'greater_than' | 'starts_with' | 'does_not_start_with' | 'ends_with' | 'does_not_end_with' | 'contains' | 'does_not_contain' | 'matches' | 'does_not_match' | 'has_any_value' | 'is_undefined' | 'matches_url' | 'does_not_match_url' | 'matches_ip' | 'does_not_match_ip' | 'any_of' | 'none_of' | 'during' | 'not_during', required: How a condition tests its value; any_of and none_of take a list, during and not_during a range, has_any_value and is_undefined no value.
            - `value` union, required
              - …
    - `draft` WidgetDraftState
      - `state` 'new' | 'draft' | 'synced', required: new: started with create_widget_draft and not saved yet; the widget exists only in this draft. draft: your unsaved changes over the saved widget. synced: the draft matches the saved widget.
      - `revision` integer, nullable: The draft's revision: 1 when it started, one more per change; null when you have no draft of this widget
      - `saved_changed` boolean, required: true: the widget was saved after your draft started, and saving would replace that save
      - `saved_by` string, nullable: Who made that save, when saved_changed; e-mail or name
      - `saved_at` string, date-time, nullable: When they saved, when saved_changed
      - `started_at` string, date-time, nullable: When this draft started; a draft that started before this conversation is unfinished work, maybe yours
      - `updated_at` string, date-time, nullable: Last change to the draft
      - `preview_url` string, nullable: One permanent page per widget: your draft while it has unsaved changes, the saved widget otherwise, refreshed as you edit; null where live previews are not set up
    - `warnings` string[], required: Informational notes about the widget itself; wording is not stable, do not parse
    - `created_at` string, date-time, nullable
    - `updated_at` string, date-time, nullable: Last change of the widget itself; a move to another folder does not change it
    - `edited_at` string, date-time, nullable: Last change made in the editor
    - `truncated` string[]: Parts shortened in the list, as paths; the card has them whole. Empty when nothing was cut
  - `next_cursor` string, nullable
  - `total` integer, required: Widgets matching the filters, the same on every page

## Other responses

- `400`: Unsupported GSC-Version
- `401`: Missing or invalid API key or access token
- `403`: Access denied
- `404`: Not found
- `422`: Validation failed
- `429`: Rate limited
- `503`: Temporarily unavailable; retry later

---

[API](https://skmtc.dev/getsitecontrol/apis/getsitecontrol-public-api.md) - [All operations](https://skmtc.dev/getsitecontrol/apis/getsitecontrol-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/getsitecontrol/apis/getsitecontrol-public-api/revisions/084fcad80e75?raw)
