Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ environments: web
status: published
feedback link: https://github.com/sigmacomputing/sigmaquickstarts/issues
tags: default
lastUpdated: 2025-07-14
lastUpdated: 2025-07-21

# Rest API Usage 02: Bookmarks
# REST API Usage 02: Bookmarks

## Overview
Duration: 5
Expand All @@ -23,7 +23,7 @@ This approach enables more personalized, collaborative analytics experiences. It
<strong>IMPORTANT:</strong><br> This QuickStart builds on the setup from "REST API Usage 01: Getting Started". If you haven’t yet cloned the repo, installed dependencies, and configured your Sigma workspace, please follow that QuickStart first.
</aside>

[REST API Usage 01: Getting Started](https://quickstarts.sigmacomputing.com/guide/embedding_rest_api_usage_01_getting%20started_started/index.html?index=..%2F..index#0)
[REST API Usage 01: Getting Started](https://quickstarts.sigmacomputing.com/guide/embedding_rest_api_usage_01_getting_started/index.html?index=..%2F..index#0)

<aside class="positive">
<strong>IMPORTANT:</strong><br> Some screens in Sigma may appear slightly different from those shown here. This is because Sigma continuously adds and enhances functionality. Rest assured—Sigma’s intuitive interface ensures that any differences won’t prevent you from completing the QuickStart successfully.
Expand Down Expand Up @@ -64,7 +64,7 @@ Duration: 5

If you haven't already, open the project in VSCode and start the Express server in terminal from the `embedding_qs_series_2_api_use_cases` folder:
```code
npm start
DEBUG=true npm start
```

The server is ready when it displays: `Server listening at http://localhost:3000`.
Expand All @@ -86,54 +86,48 @@ The embed loads but there are no bookmarks in the `Saved Bookmark` list yet. The
<img src="assets/api_bm_02.png" width="800"/>

### Create a bookmark
Let's say the `View` user has requested for the workbook only to show data for mobile phones. With this embed configuration, the `Build` user can provide that by creating a bookmark.
Let's say the `View` user has requested that the workbook only show data for mobile phones. With this embed configuration, the `Build` user can provide that by creating a bookmark.

Switching to the `Build` user, we can set a filter on the table to display only rows with `Project Types`:
Switching to the `Build` user, we can set a filter on the table to display only rows with `Product Types` > `Mobiles`:

<img src="assets/api_bm_03.png" width="800"/>

...that are `Mobiles`:

<img src="assets/api_bm_04.png" width="800"/>
<aside class="negative">
<strong>NOTE:</strong><br> The "Bookmark Name" control appears when an explore is first created.
</aside>

A few things happen when we start to interact with the table, in this case selecting a column to filter on (Product Type) and then selecting a value (Mobiles).
A few things happen when we start to interact with the table. In this case, we're selecting a column to filter on (Product Type) and then selecting a value (Mobiles).

In the console log we can see that each time, a different `exploreKey` event was emitted from Sigma. This is an important observation as we only really want to create a bookmark on the most recent `exploreKey` and this needs to be handled in the code:
In the console log, we can see that each time a different `exploreKey` event was emitted from Sigma. This is an important observation, as we only want to create a bookmark on the most recent `exploreKey`, and this needs to be handled in the code:

<img src="assets/api_bm_05.png" width="800"/>

In `api-embed-bookmarks/index.html`, we added an event listener to store the most recent `exploreKey`:
```code
window.addEventListener("message", (event) => {
if (event.data?.type === "workbook:exploreKey:available") {
latestExploreKey = event.data.exploreKey;
if (DEBUG) console.log("Received exploreKey:", latestExploreKey);
if (
data.type === "exploreCreated" ||
data.type === "workbook:exploreKey:onchange"
) {
if (data.exploreKey) {
latestExploreKey = data.exploreKey;
if (DEBUG) {
console.log("Captured exploreKey:", latestExploreKey);
console.log("Current mode at exploreKey event:", currentMode);
}
toggleBookmarkControls(currentMode === "build");
}
});
}
```

This ensures that the latest exploreKey is always stored in the global `latestExploreKey` variable.

Later, when the `Build` user clicks a `Save Bookmark` button, the value of `latestExploreKey` is passed into the API call:
```code
const response = await fetch("/api/bookmarks/create", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
workbookId,
name: bookmarkName,
exploreKey: latestExploreKey, // only the most recent value is sent
}),
});
```
Later, when the `Build` user clicks the `Save Bookmark` button, the value of `latestExploreKey` is passed into the API call.

Once we have the table filtered, the `Bookmark Name` option appears in the application header and we can give it a name (Mobile Phones) and click `Create Bookmark`:
Once we have the table filtered, we can give the bookmark a name (Mobile Phones) and click `Create Bookmark`:

<img src="assets/api_bm_06.png" width="800"/>

A popup will confirm the bookmark was created:

<img src="assets/api_bm_07.png" width="800"/>
A popup will confirm the bookmark, `Bookmark created successfully!`.

Click `Ok`.

Expand All @@ -142,78 +136,37 @@ The `Saved Bookmark` list now contains the new entry:
<img src="assets/api_bm_08.png" width="600"/>

<aside class="negative">
<strong>NOTE:</strong><br> We decided to leave the "Original Workbook" selected after creating a bookmark.Another option is to set the embed to use the newly bookmarked version. Understanding the finer points of the workflow before coding will save time and improve user adoption.
<strong>NOTE:</strong><br> We decided to leave the "Original Workbook" selected after creating a bookmark. Another option is to set the embed to use the newly bookmarked version. Understanding the finer points of the workflow before coding will save time and improve user adoption.
</aside>

We can also select the `Mobile Phones` bookmark when using the `View` user:

<img src="assets/api_bm_09.png" width="800"/>

![Footer](assets/sigma_footer.png)
<!-- END OF SECTION-->

## Project Code
Duration: 5

This QuickStart builds on the shared project structure used in "REST API Usage 01: Getting Started" and introduces new files for handling bookmark functionality.

The following files implement the logic for listing and creating bookmarks using the Sigma REST API:

### Routes Folder
**bookmarks/list.js:** Fetches all bookmarks associated with a workbook.

- Endpoint: /api/bookmarks/list?workbookUrlId=...
- Also uses `get-access-token.js` and the Sigma API endpoint `GET /v2/workbooks/{workbookId}/bookmarks`

### Helpers Folder
**create-bookmark.js:** Creates a new bookmark from a user-defined `exploreKey`. Requires `userEmail`, `workbookUrlId`, `exploreKey`, and `name`.
- Endpoint: /api/bookmarks/create-bookmark

- Also uses the Sigma API endpoint `POST /v2/workbooks/{workbookId}/bookmarks`

### api-embed-bookmarks Folder
**index.html:** Adds a dropdown menu to display saved bookmarks for the selected workbook.
- Enables Build users to name and save a bookmark for their current exploration state.
- Captures and stores the exploreKey using the `workbook:exploreKey:onchange` event.
- Applies bookmarks by updating the embed URL or by posting a `workbook:exploreKey:apply` message.

![Footer](assets/sigma_footer.png)
<!-- END OF SECTION-->

## Endpoint Operations Used
Duration: 5

The following is information about a few of the primary API endpoints used to enable the functionality demonstrated.

The JWT token process has previously been detailed in the QuickStart: [Embedding 01: Getting Started](https://quickstarts.sigmacomputing.com/guide/embedding_01_getting_started_v3/index.html?index=..%2F..index#0), so we won’t cover it again here.
### View user
We have designed the project so that the `View` user can access saved workbooks but cannot alter them or create new explorations or bookmarks.

### GET /v2/workbooks/{workbookId}/bookmarks
Retrieves all bookmarks saved for a given workbook.

Used in:<br>
`/api/bookmarks/list` route.<br>
`loadBookmarks()` function in `index.html`.

### POST /v2/workbooks/{workbookId}/bookmarks
Creates a new bookmark from a user-defined exploration state.

- Used in `/api/bookmarks/create-bookmark` route.
- Triggered by the "Create Bookmark" button in `index.html`

Requires:
- name: Label for the bookmark
- exploreKey: The current explore state from the embedded workbook
- userEmail: Used for scoping permissions
We do this by first disabling the workbook menus in the `.env` file when the `View` user is selected:
```code
HIDE_FOLDER_NAVIGATION=false
HIDE_MENU=false
MENU_POSITION=none
```

Returns: Metadata about the created bookmark
In the `index.html` page we have a `toggleBookmarkControls` function that enforces:

### isShared Parameter – What It Means
When creating a bookmark via the Sigma API `POST /v2/workbooks/{workbookId}/bookmarks`, you can include the optional `isShared` flag:
- For Build Users: currentMode === "build" returns true → bookmark controls shown
- For View Users: currentMode === "build" returns false → bookmark controls hidden
- UI Effects:
- Hides entire bookmark controls div (display: none)
- Disables create button (disabled = true)
- Clears bookmark name input

- **true:** The bookmark is shared and visible to all users who have access to the workbook.
- **false:** The bookmark is private and only visible to the user who created it.
This ensures `View Users` cannot see or interact with bookmark creation controls, even if they somehow interact with the embedded content.

In this QuickStart, we default to private bookmarks although `View` users were able to access the bookmark list in this design. We’ll explore another shared bookmarks design and additional collaboration patterns in the next QuickStart.
<aside class="positive">
<strong>IMPORTANT:</strong><br> We will rely on the information in the README for the implementation details and not discuss them in this QuickStart. A button is provided on the webpage for easy access.
</aside>

![Footer](assets/sigma_footer.png)
<!-- END OF SECTION-->
Expand All @@ -223,26 +176,25 @@ Duration: 5

After creating several bookmarks for testing you may want to delete them when done. This can be done in Sigma's [API Reference](https://help.sigmacomputing.com/reference/get-started-sigma-api), but that is one at a time.

To automate this, we created a script that will:

- Accept the short workbookUrlId as a CLI argument
- Resolve it to the full UUID
- Fetch all bookmarks
- Delete them one-by-one
- Handle errors and shows progress
To automate this, we created a script under a page button.

<aside class="positive">
<strong>IMPORTANT:</strong><br> Be very careful as this will permanently delete all bookmarks for the specified workbook. Use at your own risk against a production instance of Sigma.
<strong>IMPORTANT:</strong><br> Be very careful as this will permanently delete all bookmarks for the specified workbook. Use at your own risk if using against a production instance of Sigma.
</aside>

Open terminal and run the following command, replacing {TARGET workbookID} with your actual workbook ID:
```code
node ./public/tools/delete-all-bookmarks.js {TARGET workbookID}
```
Select the `Build` user and a workbook to target.

`Clear All Bookmarks` calls the script for you. The fetch called is `api\route\bookmarks\clear-all`.

The output will list the bookmarks that were deleted:
<img src="assets/api_bm_11.png" width="800"/>

<img src="assets/api_bm_10.png" width="800"/>
The console log will list the bookmarks that were deleted:
```code
Fetching bookmarks from Sigma API: https://aws-api.sigmacomputing.com/v2/workbooks/0e51172a-a4c0-4954-8c8c-9d854dcf4434/bookmarks
Found 1 bookmarks in Sigma to delete
✅ Deleted Sigma bookmark: Mobile Phones (879c3131-eee6-4263-8df1-4e1a4be7178a)
✅ Clear all bookmarks completed - deleted 1 bookmarks
```

![Footer](assets/sigma_footer.png)
<!-- END OF SECTION-->
Expand All @@ -257,6 +209,7 @@ In this QuickStart, we demonstrated how to extend your Sigma embedding experienc
- Listing all existing bookmarks for a selected workbook.
- Applying a saved bookmark using outbound `postMessage` events to update the embed in real time.
- Restricting bookmark functionality to Build users only, while still allowing View users to apply saved bookmarks.
- Bulk deletion of bookmarks for a selected workbook.

This QuickStart builds on the foundational setup from the previous one and introduces a practical use case for interactive, personalized embedding with the Sigma API.

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading