# Bookmarks

## Overview

The API includes built-in support for bookmarking activities. Here's a quick example of how to use the bookmark API.

### Adding Bookmarks

```js label="JavaScript"
// Adding a bookmark to a new folder
const bookmark = await client.addBookmark({
  activity_id: "activity_123",
});

// Adding to an existing folder
const bookmarkWithFolder = await client.addBookmark({
  activity_id: "activity_123",
  folder_id: "folder_456",
});

// Update a bookmark (without a folder initially) - add custom data and move it to a new folder
const updatedBookmark = await client.updateBookmark({
  activity_id: "activity_123",
  folder_id: "<old folder id>",
  new_folder: {
    name: "New folder name",
    custom: {
      icon: "📂",
    },
  },
  custom: {
    color: "blue",
  },
});

// Update a bookmark - move it from one existing folder to another existing folder
const movedBookmark = await client.updateBookmark({
  activity_id: "activity_123",
  folder_id: "<old folder id>",
  new_folder_id: "<new folder id>",
});
```

```js label="Node.js"
// Adding a bookmark to a new folder
const bookmark = await client.feeds.addBookmark({
  activity_id: "activity_123",
  user_id: "<user_id>",
});

// Adding to an existing folder
const bookmarkWithFolder = await client.feeds.addBookmark({
  activity_id: "activity_123",
  folder_id: "folder_456",
  user_id: "<user_id>",
});

// Update a bookmark (without a folder initially) - add custom data and move it to a new folder
const updatedBookmark = await client.feeds.updateBookmark({
  activity_id: "activity_123",
  folder_id: "<old folder id>",
  new_folder: {
    name: "New folder name",
    custom: {
      icon: "📂",
    },
  },
  custom: {
    color: "blue",
  },
  user_id: "<user_id>",
});

// Update a bookmark - move it from one existing folder to another existing folder
const movedBookmark = await client.feeds.updateBookmark({
  activity_id: "activity_123",
  folder_id: "<old folder id>",
  new_folder_id: "<new folder id>",
  user_id: "<user_id>",
});
```

### Removing Bookmarks

```js label="JavaScript"
// Removing a bookmark
await client.deleteBookmark({
  activity_id: activityId,
});

// When you read a feed we include the bookmark
const response = await feed.getOrCreate({ watch: true });
console.log(feed.state.getLatestValue().activities?.[0].own_bookmarks);
console.log(feed.state.getLatestValue().activities?.[0].bookmark_count);
```

```js label="Node.js"
// Removing a bookmark
await serverClient.feeds.deleteBookmark({
  activity_id: activityId,
  user_id: testUser2.id,
});

// When you read a feed we include the bookmark
const response = await feed.getOrCreate({ user_id: "sara" });
console.log(results.activities[0].own_bookmarks);
console.log(results.activities[0].bookmark_count);
```

### Querying Bookmarks

```js label="JavaScript"
// Query bookmarks
const firstPage = await client.queryBookmarks({
  limit: 2,
});

// Get next page
const secondPage = await client.queryBookmarks({
  limit: 2,
  next: firstPage.next,
});

// Query by activity ID
const response = await client.queryBookmarks({
  filter: {
    activity_id: "activity_123",
  },
});

// Query by folder ID
const response = await client.queryBookmarks({
  filter: {
    folder_id: "folder_456",
  },
});
```

```js label="Node.js"
// Query bookmarks
const firstPage = await client.feeds.queryBookmarks({
  filter: {
    user_id: "<user id>",
  },
  limit: 2,
});

// Get next page
const secondPage = await client.feeds.queryBookmarks({
  filter: {
    user_id: "<user id>",
  },
  limit: 2,
  next: firstPage.next,
});

// Query by activity ID
const response = await client.feeds.queryBookmarks({
  filter: {
    user_id: "<user id>",
    activity_id: "activity_123",
  },
});

// Query by folder ID
const response = await client.feeds.queryBookmarks({
  filter: {
    user_id: "<user id>",
    folder_id: "folder_456",
  },
});
```

#### Bookmarks Queryable Built-In Fields

| name          | type                                              | description                                  | supported operations                | example                                               |
| ------------- | ------------------------------------------------- | -------------------------------------------- | ----------------------------------- | ----------------------------------------------------- |
| `user_id`     | string or list of strings                         | The ID of the user who owns the bookmark     | `$in`, `$eq`                        | `{ user_id: { $eq: 'user_123' } }`                    |
| `activity_id` | string or list of strings                         | The ID of the activity that was bookmarked   | `$in`, `$eq`                        | `{ activity_id: { $eq: 'activity_123' } }`            |
| `folder_id`   | string or list of strings                         | The ID of the folder containing the bookmark | `$eq`, `$in`, `$exists`             | `{ folder_id: { $exists: true } }`                    |
| `created_at`  | string, must be formatted as an RFC3339 timestamp | The time the bookmark was created            | `$eq`, `$gt`, `$gte`, `$lt`, `$lte` | `{ created_at: { $gte: '2023-12-04T09:30:20.45Z' } }` |
| `updated_at`  | string, must be formatted as an RFC3339 timestamp | The time the bookmark was last updated       | `$eq`, `$gt`, `$gte`, `$lt`, `$lte` | `{ updated_at: { $gte: '2023-12-04T09:30:20.45Z' } }` |

### Querying Bookmark Folders

```js label="JavaScript"
// Query bookmark folders
const firstPage = await client.queryBookmarkFolders({
  limit: 2,
});

// Get next page
const secondPage = await client.queryBookmarkFolders({
  limit: 2,
  next: firstPage.next,
});

const response = await client.queryBookmarkFolders({
  filter: {
    folder_name: {
      $contains: "project",
    },
  },
  limit: 2,
  next: firstPage.next,
});
```

```js label="Node.js"
// Query bookmark folders
const firstPage = await client.feeds.queryBookmarkFolders({
  filter: {
    user_id: "<user id>",
  },
  limit: 2,
});

// Get next page
const secondPage = await client.feeds.queryBookmarkFolders({
  filter: {
    user_id: "<user id>",
  },
  limit: 2,
  next: firstPage.next,
});

const response = await client.feeds.queryBookmarkFolders({
  filter: {
    user_id: "<user id>",
    folder_name: {
      $contains: "project",
    },
  },
  limit: 2,
  next: firstPage.next,
});
```

#### Bookmark Folders Queryable Built-In Fields

| name          | type                                              | description                            | supported operations                | example                                               |
| ------------- | ------------------------------------------------- | -------------------------------------- | ----------------------------------- | ----------------------------------------------------- |
| `user_id`     | string or list of strings                         | The ID of the user who owns the folder | `$in`, `$eq`                        | `{ user_id: { $eq: 'user_123' } }`                    |
| `folder_name` | string or list of strings                         | The name of the bookmark folder        | `$eq`, `$in`, `$contains`           | `{ folder_name: { $contains: 'work' } }`              |
| `created_at`  | string, must be formatted as an RFC3339 timestamp | The time the folder was created        | `$eq`, `$gt`, `$gte`, `$lt`, `$lte` | `{ created_at: { $gte: '2023-12-04T09:30:20.45Z' } }` |
| `updated_at`  | string, must be formatted as an RFC3339 timestamp | The time the folder was last updated   | `$eq`, `$gt`, `$gte`, `$lt`, `$lte` | `{ updated_at: { $gte: '2023-12-04T09:30:20.45Z' } }` |

### Managing Bookmark Folders

#### Update bookmark folder

The endpoint performs a partial update: only the fields you include in the request are changed, and each of those fields is completely overwritten.

Updating a bookmark folder sends `feeds.bookmark_folder.updated` event to the clients of the user who owns the folder. There are no default client-side SDK handlers for this event, but you can add a custom handler if your UI needs to be updated.

#### Delete bookmark folder

Use the delete bookmark folder endpoint to remove a folder by ID. All bookmarks in that folder are removed.

Deleting a bookmark folder sends `feeds.bookmark_folder.deleted` event to the clients of the user who owns the folder. There are no default client-side SDK handlers for this event, but you can add a custom handler if your UI needs to be updated.

```js label="JavaScript"
const bookmark = (
  await client.addBookmark({
    activity_id: activity.id,
    new_folder: {
      name: "Breakfast recipes",
      custom: {
        icon: "🍳",
      },
    },
  })
).bookmark;

const updatedFolder = (
  await client.updateBookmarkFolder({
    folder_id: bookmark.folder?.id,
    name: "Sweet Breakfast Recipes",
    custom: {
      icon: "🥞",
    },
  })
).bookmark_folder;

await client.deleteBookmarkFolder({
  folder_id: updatedFolder.id,
});
```

```js label="Node.js"
const bookmark = (
  await client.feeds.addBookmark({
    activity_id: activity.id,
    user_id: "<user_id>",
    new_folder: {
      name: "Breakfast recipes",
      custom: {
        icon: "🍳",
      },
    },
  })
).bookmark;

const updatedFolder = (
  await client.feeds.updateBookmarkFolder({
    folder_id: bookmark.folder?.id,
    name: "Sweet Breakfast Recipes",
    custom: {
      icon: "🥞",
    },
  })
).bookmark_folder;

await client.feeds.deleteBookmarkFolder({
  folder_id: updatedFolder.id,
});
```

---

For the most recent version of this documentation, visit [https://getstream.io/activity-feeds/docs/node/bookmarks/](https://getstream.io/activity-feeds/docs/node/bookmarks/).