# 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

<Tabs>

```swift label="Swift"
// Adding a bookmark to a new folder
let bookmark = try await feed.addBookmark(activityId: "activity_123")
// Adding to an existing folder
let bookmarkWithFolder = try await feed.addBookmark(
    activityId: "activity_123",
    request: .init(folderId: "folder_456")
)
// Update a bookmark (without a folder initially) - add custom data and move it to a new folder
let updatedBookmark = try await feed.updateBookmark(
    activityId: "activity_123",
    request: .init(
        custom: ["color": "blue"],
        newFolder: .init(
            custom: ["icon": "📁"],
            name: "New folder name"
        )
    )
)
// Update a bookmark - move it from one existing folder to another existing folder
let movedBookmark = try await feed.updateBookmark(
    activityId: "activity_123",
    request: .init(
        folderId: "folder_456",
        newFolderId: "folder_789"
    )
)
```

```kotlin label="Kotlin"
// Adding a bookmark to a new folder
val bookmark: Result<BookmarkData> = feed.addBookmark(activityId = "activity_123")

// Adding to an existing folder
val bookmarkWithFolder: Result<BookmarkData> = feed.addBookmark(
    activityId = "activity_123",
    request = AddBookmarkRequest(folderId = "folder_456")
)

// Update a bookmark (without a folder initially) - add custom data and move it to a new folder
val updatedBookmark: Result<BookmarkData> = feed.updateBookmark(
    activityId = "activity_123",
    request = UpdateBookmarkRequest(
        custom = mapOf("color" to "blue"),
        newFolder = AddFolderRequest(
            custom = mapOf("icon" to "📁"),
            name = "New folder name"
        )
    )
)

// Update a bookmark - move it from one existing folder to another existing folder
val movedBookmark: Result<BookmarkData> = feed.updateBookmark(
    activityId = "activity_123",
    request = UpdateBookmarkRequest(
        folderId = "folder_456",
        newFolderId = "folder_789"
    )
)
```

```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="React"
// 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="React Native"
// 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>",
});
```

```dart label="Dart"
// Adding a bookmark to a new folder
final bookmark = await feed.addBookmark(activityId: 'activity_123');
// Adding to an existing folder
final bookmarkWithFolder = await feed.addBookmark(
  activityId: 'activity_123',
  request: const AddBookmarkRequest(folderId: 'folder_456'),
);
// Update a bookmark (without a folder initially) - add custom data and move it to a new folder
final updatedBookmark = await feed.updateBookmark(
  activityId: 'activity_123',
  request: const UpdateBookmarkRequest(
    custom: {'color': 'blue'},
    newFolder: AddFolderRequest(
      custom: {'icon': '📁'},
      name: 'New folder name',
    ),
  ),
);
// Update a bookmark - move it from one existing folder to another existing folder
final movedBookmark = await feed.updateBookmark(
  activityId: 'activity_123',
  request: const UpdateBookmarkRequest(
    folderId: 'folder_456',
    newFolderId: 'folder_789',
  ),
);
```

```js label="Node"
// 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>",
});
```

```go label="Go"
// Adding a bookmark to a new folder
_, err = client.Feeds().AddBookmark(context.Background(), activityID, &getstream.AddBookmarkRequest{
  UserID: getstream.PtrTo("john"),
})
if err != nil {
  log.Fatal("Error adding bookmark:", err)
}

// Adding to an existing folder
_, err = client.Feeds().AddBookmark(context.Background(), activityID, &getstream.AddBookmarkRequest{
  FolderID: getstream.PtrTo("folder_456"),
  UserID:   getstream.PtrTo("john"),
})
if err != nil {
  log.Fatal("Error adding bookmark to folder:", err)
}

// Update a bookmark (without a folder initially) - add custom data and move it to a new folder
_, err = client.Feeds().UpdateBookmark(context.Background(), activityID, &getstream.UpdateBookmarkRequest{
  FolderID: getstream.PtrTo("old folder id"),
  NewFolder: &getstream.AddFolderRequest{
    Name: "New folder name",
    Custom: map[string]any{
      "icon": "📂",
    },
  },
  Custom: map[string]any{
    "color": "blue",
  },
  UserID: getstream.PtrTo("john"),
})
if err != nil {
  log.Fatal("Error updating bookmark:", err)
}

// Update a bookmark - move it from one existing folder to another existing folder
_, err = client.Feeds().UpdateBookmark(context.Background(), activityID, &getstream.UpdateBookmarkRequest{
  FolderID:    getstream.PtrTo("old folder id"),
  NewFolderID: getstream.PtrTo("new folder id"),
  UserID:      getstream.PtrTo("john"),
})
if err != nil {
  log.Fatal("Error moving bookmark:", err)
}
```

```java label="Java"
AddBookmarkRequest bookmarkRequest =
    AddBookmarkRequest.builder()
        .userID(testUserId)
        .newFolder(AddFolderRequest.builder().name("test-bookmarks1").build())
        .build();

AddBookmarkResponse response =
    feeds.addBookmark(activityId, bookmarkRequest).execute().getData();
```

```php label="php"
// Adding a bookmark to a new folder
$response = $feedsClient->addBookmark(
    'activity_123',
    new GeneratedModels\AddBookmarkRequest(
        userID: 'user_123',
        newFolder: new GeneratedModels\AddFolderRequest(name: 'New folder name')
    )
);

// Adding to an existing folder
$response = $feedsClient->addBookmark(
    'activity_123',
    new GeneratedModels\AddBookmarkRequest(
        userID: 'user_123',
        folderID: 'folder_456'
    )
);

// Update a bookmark (without a folder initially) - add custom data and move it to a new folder
$response = $feedsClient->updateBookmark(
    'activity_123',
    new GeneratedModels\UpdateBookmarkRequest(
        userID: 'user_123',
        custom: (object)['color' => 'blue'],
        newFolder: new GeneratedModels\AddFolderRequest(
            name: 'New folder name',
            custom: (object)['icon' => '📁']
        )
    )
);

// Update a bookmark - move it from one existing folder to another existing folder
$response = $feedsClient->updateBookmark(
    'activity_123',
    new GeneratedModels\UpdateBookmarkRequest(
        userID: 'user_123',
        folderID: 'folder_456',
        newFolderID: 'folder_789'
    )
);
```

```csharp label="C#"
var response = await _feedsV3Client.AddBookmarkAsync(
    activityId,
    new AddBookmarkRequest
    {
        UserID = _testUserId,
        NewFolder = new AddFolderRequest { Name = "test-bookmarks1" }
    }
);
```

```python label="Python"
response = self.client.feeds.add_bookmark(
    activity_id,
    user_id=self.test_user_id,
    new_folder=AddFolderRequest(name="test-bookmarks1"),
)
```

```ruby label="Ruby"
# Adding a bookmark to a new folder
bookmark_request = GetStream::Generated::Models::AddBookmarkRequest.new(
  user_id: 'user123',
  new_folder: GetStream::Generated::Models::AddFolderRequest.new(
    name: 'test-bookmarks1'
  )
)

response = client.feeds.add_bookmark(activity_id, bookmark_request)

# Adding to an existing folder
bookmark_with_folder_request = GetStream::Generated::Models::AddBookmarkRequest.new(
  user_id: 'user123',
  folder_id: 'folder_456'
)

response = client.feeds.add_bookmark(activity_id, bookmark_with_folder_request)

# Update a bookmark (without a folder initially) - add custom data and move it to a new folder
update_request = GetStream::Generated::Models::UpdateBookmarkRequest.new(
  user_id: 'user123',
  custom: {
    color: 'blue'
  },
  new_folder: GetStream::Generated::Models::AddFolderRequest.new(
    name: 'New folder name',
    custom: {
      icon: '📁'
    }
  )
)

response = client.feeds.update_bookmark(activity_id, update_request)

# Update a bookmark - move it from one existing folder to another existing folder
move_request = GetStream::Generated::Models::UpdateBookmarkRequest.new(
  user_id: 'user123',
  folder_id: 'folder_456',
  new_folder_id: 'folder_789'
)

response = client.feeds.update_bookmark(activity_id, move_request)
```

</Tabs>

### Removing Bookmarks

<Tabs>

```swift label="Swift"
// Removing a bookmark
try await feed.deleteBookmark(
    activityId: "activity_123",
    folderId: "folder_456"
)

// When you read a feed we include the bookmark
try await feed.getOrCreate()
print(feed.state.activities[0].ownBookmarks)
```

```kotlin label="Kotlin"
// Removing a bookmark
feed.deleteBookmark(
    activityId = "activity_123",
    folderId = "folder_456"
)

// When you read a feed we include the bookmark
feed.getOrCreate()
feed.state.activities.collect { activities ->
    println(activities.first().ownBookmarks)
}
```

```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="React"
// 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="React Native"
// 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);
```

```dart label="Dart"
// Removing a bookmark
await feed.deleteBookmark(activityId: 'activity_123', folderId: 'folder_456');
// When you read a feed we include the bookmark
final feedData = await feed.getOrCreate();
print(feed.state.activities[0].ownBookmarks);
```

```js label="Node"
// 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);
```

```go label="Go"
_, err = client.Feeds().DeleteBookmark(context.Background(), activityID, &getstream.DeleteBookmarkRequest{
  FolderID: getstream.PtrTo(folderID),
  UserID: getstream.PtrTo("john"),
})
```

```java label="Java"
UpdateBookmarkRequest updateRequest =
    UpdateBookmarkRequest.builder().folderID(folderID).userID(testUserId).build();

UpdateBookmarkResponse response =
    feeds.updateBookmark(activityId, updateRequest).execute().getData();
```

```php label="php"
// Removing a bookmark
$response = $feedsClient->deleteBookmark(
    'activity_123',
    'folder_456',
    'user_123'
);

// When you read a feed we include the bookmark
$feedResponse = $feedsClient->getOrCreateFeed('user', 'user_123', new GeneratedModels\GetOrCreateFeedRequest(
  userID: 'user_123'
));
$activities = $feedResponse->getData()->activities;
echo json_encode($activities[0]->ownBookmarks);
echo $activities[0]->bookmarkCount;
```

```csharp label="C#"
var response = await _feedsV3Client.UpdateBookmarkAsync(
    activityId,
    new UpdateBookmarkRequest
    {
        UserID = _testUserId,
        FolderID = folderId  // Use existing folder ID, not create new folder
    }
);
```

```python label="Python"
bookmark_data = bookmark_response.data
folder_id = bookmark_data.bookmark.folder.id
response = self.client.feeds.update_bookmark(
    activity_id, folder_id=folder_id, user_id=self.test_user_id
)
```

```ruby label="Ruby"
# Removing a bookmark
response = client.feeds.delete_bookmark(activity_id, folder_id, 'user123')

# When you read a feed we include the bookmark
feed_response = client.feeds.get_or_create('user', 'user123')
puts feed_response.activities[0].own_bookmarks
puts feed_response.activities[0].bookmark_count
```

</Tabs>

### Querying Bookmarks

<Tabs>

```swift label="Swift"
// Query bookmarks
let query = BookmarksQuery(limit: 5)
let bookmarkList = client.bookmarkList(for: query)
let page1 = try await bookmarkList.get()

// Get next page
let page2 = try await bookmarkList.queryMoreBookmarks(limit: 3)

// Query by activity ID
let activityBookmarkList = client.bookmarkList(
    for: .init(
        filter: .equal(.activityId, "activity_123")
    )
)
let activityBookmarks = try await activityBookmarkList.get()

// Query by folder ID
let folderBookmarkList = client.bookmarkList(
    for: .init(
        filter: .equal(.folderId, "folder_456")
    )
)
let folderBookmarks = try await folderBookmarkList.get()
```

```kotlin label="Kotlin"
// Query bookmarks
val query = BookmarksQuery(limit = 5)
val bookmarkList = client.bookmarkList(query = query)
val page1: Result<List<BookmarkData>> = bookmarkList.get()

// Get next page
val page2: Result<List<BookmarkData>> = bookmarkList.queryMoreBookmarks(limit = 3)

// Query by activity ID
val activityBookmarkList = client.bookmarkList(
    query = BookmarksQuery(
        filter = BookmarksFilterField.activityId.equal("activity_123")
    )
)
val activityBookmarks: Result<List<BookmarkData>> = activityBookmarkList.get()

// Query by folder ID
val folderBookmarkList = client.bookmarkList(
    query = BookmarksQuery(
        filter = BookmarksFilterField.folderId.equal("folder_456")
    )
)
val folderBookmarks: Result<List<BookmarkData>> = folderBookmarkList.get()
```

```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="React"
// 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="React Native"
// 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",
  },
});
```

```dart label="Dart"
// Query bookmarks
const query = BookmarksQuery(limit: 5);
final bookmarkList = client.bookmarkList(query);
final page1 = await bookmarkList.get();
// Get next page
final page2 = await bookmarkList.queryMoreBookmarks(limit: 3);
// Query by activity ID
final activityBookmarkList = client.bookmarkList(
  const BookmarksQuery(
    filter: Filter.equal(BookmarksFilterField.activityId, 'activity_123'),
  ),
);
final activityBookmarks = await activityBookmarkList.get();
// Query by folder ID
final folderBookmarkList = client.bookmarkList(
  const BookmarksQuery(
    filter: Filter.equal(BookmarksFilterField.folderId, 'folder_456'),
  ),
);
final folderBookmarks = await folderBookmarkList.get();
```

```js label="Node"
// 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",
  },
});
```

```go label="Go"
// Query bookmarks
firstPage, err := client.Feeds().QueryBookmarks(context.Background(), &getstream.QueryBookmarksRequest{
  Filter: map[string]any{
    "user_id": "john",
  },
  Limit: getstream.PtrTo(2),
})
if err != nil {
  log.Fatal("Error querying bookmarks:", err)
}

// Get next page
_, err = client.Feeds().QueryBookmarks(context.Background(), &getstream.QueryBookmarksRequest{
  Filter: map[string]any{
    "user_id": "john",
  },
  Limit: getstream.PtrTo(2),
  Next:  firstPage.Data.Next,
})
if err != nil {
  log.Fatal("Error querying next page bookmarks:", err)
}

// Query by activity ID
_, err = client.Feeds().QueryBookmarks(context.Background(), &getstream.QueryBookmarksRequest{
  Filter: map[string]any{
    "user_id":     "john",
    "activity_id": activityID,
  },
})
if err != nil {
  log.Fatal("Error querying bookmarks by activity ID:", err)
}

// Query by folder ID
_, err = client.Feeds().QueryBookmarks(context.Background(), &getstream.QueryBookmarksRequest{
  Filter: map[string]any{
    "user_id":   "john",
    "folder_id": folderID,
  },
})
if err != nil {
  log.Fatal("Error querying bookmarks by folder ID:", err)
}
```

```java label="Java"
Map<String, Object> filter = new HashMap<>();
filter.put("user_id", testUserId);

QueryBookmarksRequest request =
    QueryBookmarksRequest.builder().limit(10).filter(filter).build();

QueryBookmarksResponse response = feeds.queryBookmarks(request).execute().getData();
```

```php label="php"
// Query bookmarks
$firstPage = $feedsClient->queryBookmarks(
    new GeneratedModels\QueryBookmarksRequest(
        limit: 2,
        filter: (object)['user_id' => 'user_123']
    )
);

// Get next page
$secondPage = $feedsClient->queryBookmarks(
    new GeneratedModels\QueryBookmarksRequest(
        limit: 2,
        next: $firstPage->getData()->next,
        filter: (object)['user_id' => 'user_123']
    )
);

// Query by activity ID
$response = $feedsClient->queryBookmarks(
    new GeneratedModels\QueryBookmarksRequest(
        filter: (object)[
            'user_id' => 'user_123',
            'activity_id' => 'activity_123'
        ]
    )
);

// Query by folder ID
$response = $feedsClient->queryBookmarks(
    new GeneratedModels\QueryBookmarksRequest(
        filter: (object)[
            'user_id' => 'user_123',
            'folder_id' => 'folder_456'
        ]
    )
);
```

```csharp label="C#"
var response = await _feedsV3Client.QueryBookmarksAsync(
    new QueryBookmarksRequest
    {
        Limit = 10,
        Filter = new Dictionary<string, object> { ["user_id"] = _testUserId }
    }
);
```

```python label="Python"
response = self.client.feeds.query_bookmarks(
    limit=10, filter={"user_id": self.test_user_id}
)
```

```ruby label="Ruby"
# Query bookmarks
query_request = GetStream::Generated::Models::QueryBookmarksRequest.new(
  limit: 10,
  filter: {
    user_id: 'user123'
  }
)

response = client.feeds.query_bookmarks(query_request)

# Query by activity ID
activity_query_request = GetStream::Generated::Models::QueryBookmarksRequest.new(
  filter: {
    user_id: 'user123',
    activity_id: 'activity_123'
  }
)

response = client.feeds.query_bookmarks(activity_query_request)

# Query by folder ID
folder_query_request = GetStream::Generated::Models::QueryBookmarksRequest.new(
  filter: {
    user_id: 'user123',
    folder_id: 'folder_456'
  }
)

response = client.feeds.query_bookmarks(folder_query_request)
```

</Tabs>

#### 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

<Tabs>

```swift label="Swift"
// Query bookmark folders
let query = BookmarkFoldersQuery(limit: 5)
let bookmarkFolderList = client.bookmarkFolderList(for: query)
let page1 = try await bookmarkFolderList.get()

// Get next page
let page2 = try await bookmarkFolderList.queryMoreBookmarkFolders(limit: 3)

// Query by folder name (partial matching)
let projectFolderList = client.bookmarkFolderList(
    for: .init(
        filter: .contains(.folderName, "project")
    )
)
let projectFolders = try await projectFolderList.get()
```

```kotlin label="Kotlin"
// Query bookmark folders
val query = BookmarkFoldersQuery(limit = 5)
val bookmarkFolderList = client.bookmarkFolderList(query = query)
val page1: Result<List<BookmarkFolderData>> = bookmarkFolderList.get()

// Get next page
val page2: Result<List<BookmarkFolderData>> = bookmarkFolderList.queryMoreBookmarkFolders(limit = 3)

// Query by folder name (partial matching)
val projectFolderList = client.bookmarkFolderList(
    query = BookmarkFoldersQuery(
        filter = BookmarkFoldersFilterField.folderName.contains("project")
    )
)
val projectFolders: Result<List<BookmarkFolderData>> = projectFolderList.get()
```

```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="React"
// 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="React Native"
// 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,
});
```

```dart label="Dart"
// Query bookmark folders
const query = BookmarkFoldersQuery(limit: 5);
final bookmarkFolderList = client.bookmarkFolderList(query);
final page1 = await bookmarkFolderList.get();
// Get next page
final page2 = await bookmarkFolderList.queryMoreBookmarkFolders(limit: 3);
// Query by folder name (partial matching)
final projectFolderList = client.bookmarkFolderList(
  const BookmarkFoldersQuery(
    filter: Filter.contains(BookmarkFoldersFilterField.name, 'project'),
  ),
);
final projectFolders = await projectFolderList.get();
```

```js label="Node"
// 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,
});
```

```go label="Go"
// Query bookmark folders
firstPage, err := client.Feeds().QueryBookmarkFolders(context.Background(), &getstream.QueryBookmarkFoldersRequest{
  Filter: map[string]any{
    "user_id": "<user id>",
  },
  Limit: getstream.PtrTo(2),
})
if err != nil {
  log.Fatal("Error querying bookmark folders:", err)
}
// Get next page
_, err = client.Feeds().QueryBookmarkFolders(context.Background(), &getstream.QueryBookmarkFoldersRequest{
  Filter: map[string]any{
    "user_id": "<user id>",
  },
  Limit: getstream.PtrTo(2),
  Next:  firstPage.Data.Next,
})
if err != nil {
  log.Fatal("Error querying bookmark folders second page:", err)
}

// Query with folder name filter
_, err = client.Feeds().QueryBookmarkFolders(context.Background(), &getstream.QueryBookmarkFoldersRequest{
  Filter: map[string]any{
    "user_id": "<user id>",
    "folder_name": map[string]any{
      "$contains": "project",
    },
  },
  Limit: getstream.PtrTo(2),
  Next:  firstPage.Data.Next,
})
if err != nil {
  log.Fatal("Error querying bookmark folders with filter:", err)
}
```

```java label="Java"
Map<String, Object> filter = new HashMap<>();
filter.put("user_id", testUserId);

QueryBookmarksRequest request =
    QueryBookmarksRequest.builder().limit(10).filter(filter).build();

QueryBookmarksResponse response = feeds.queryBookmarks(request).execute().getData();
```

```php label="php"
// Query bookmark folders
$firstPage = $feedsClient->queryBookmarkFolders(
    new GeneratedModels\QueryBookmarkFoldersRequest(
        limit: 2,
        filter: (object)['user_id' => 'user_123']
    )
);

// Get next page
$secondPage = $feedsClient->queryBookmarkFolders(
    new GeneratedModels\QueryBookmarkFoldersRequest(
        limit: 2,
        next: $firstPage->getData()->next,
        filter: (object)['user_id' => 'user_123']
    )
);

// Query by folder name (partial matching)
$response = $feedsClient->queryBookmarkFolders(
    new GeneratedModels\QueryBookmarkFoldersRequest(
        filter: (object)[
            'user_id' => 'user_123',
            'folder_name' => [
                '$contains' => 'project'
            ]
        ],
        limit: 2
    )
);
```

```csharp label="C#"
var response = await _feedsV3Client.QueryBookmarksAsync(
    new QueryBookmarksRequest
    {
        Limit = 10,
        Filter = new Dictionary<string, object> { ["user_id"] = _testUserId }
    }
);
```

```python label="Python"
response = self.client.feeds.query_bookmarks(
    limit=10, filter={"user_id": self.test_user_id}
)
```

```ruby label="Ruby"
# Query bookmarks
query_request = GetStream::Generated::Models::QueryBookmarksRequest.new(
  limit: 10,
  filter: {
    user_id: 'user123'
  }
)

response = client.feeds.query_bookmarks(query_request)

# Query by activity ID
activity_query_request = GetStream::Generated::Models::QueryBookmarksRequest.new(
  filter: {
    user_id: 'user123',
    activity_id: 'activity_123'
  }
)

response = client.feeds.query_bookmarks(activity_query_request)

# Query by folder ID
folder_query_request = GetStream::Generated::Models::QueryBookmarksRequest.new(
  filter: {
    user_id: 'user123',
    folder_id: 'folder_456'
  }
)

response = client.feeds.query_bookmarks(folder_query_request)
```

</Tabs>

#### 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.

<Tabs>

```swift label="Swift"
// Add a bookmark with a new folder
let bookmark = try await feed.addBookmark(
    activityId: activity.id,
    request: .init(newFolder: .init(name: "Breakfast recipes", custom: ["icon": "🍳"]))
)

// Update the folder
let updatedFolder = try await client.updateBookmarkFolder(
    folderId: bookmark.folder!.id,
    request: .init(name: "Sweet Breakfast Recipes", custom: ["icon": "🥞"])
)

// Delete the folder (and all bookmarks in it)
try await client.deleteBookmarkFolder(folderId: updatedFolder.id)
```

```kotlin label="Kotlin"
// Add a bookmark with a new folder
val bookmark = feed.addBookmark(
    activityId = activity.id,
    request = AddBookmarkRequest(newFolder = AddFolderRequest(name = "Breakfast recipes", custom = mapOf("icon" to "🍳"))
)

// Update the folder
val updatedFolder = client.updateBookmarkFolder(
    folderId = bookmark.getOrThrow().folder!!.id,
    request = UpdateBookmarkFolderRequest(name = "Sweet Breakfast Recipes", custom = mapOf("icon" to "🥞"))
)

// Delete the folder (and all bookmarks in it)
client.deleteBookmarkFolder(folderId = updatedFolder.getOrThrow().id)
```

```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="React"
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="React Native"
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,
});
```

```dart label="Dart"
// Add a bookmark with a new folder
final bookmark = await feed.addBookmark(
  activityId: activity.id,
  request: AddBookmarkRequest(
    newFolder: AddFolderRequest(
      name: 'Breakfast recipes',
      custom: {'icon': '🍳'},
    ),
  ),
);

// Update the folder
final updatedFolder = await client.updateBookmarkFolder(
  folderId: bookmark.folder!.id,
  request: UpdateBookmarkFolderRequest(
    name: 'Sweet Breakfast Recipes',
    custom: {'icon': '🥞'},
  ),
);

// Delete the folder (and all bookmarks in it)
await client.deleteBookmarkFolder(folderId: updatedFolder.id);
```

```js label="Node"
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,
});
```

```go label="Go"
// Add a bookmark with a new folder
addResp, err := client.Feeds().AddBookmark(context.Background(), activityID, &getstream.AddBookmarkRequest{
  UserID: getstream.PtrTo("john"),
  NewFolder: &getstream.AddFolderRequest{
    Name:   "Breakfast recipes",
    Custom: map[string]any{"icon": "🍳"},
  },
})
if err != nil {
  log.Fatal(err)
}
folderID := addResp.Data.Bookmark.Folder.ID

// Update the folder
updateResp, err := client.Feeds().UpdateBookmarkFolder(context.Background(), folderID, &getstream.UpdateBookmarkFolderRequest{
  Name:   getstream.PtrTo("Sweet Breakfast Recipes"),
  Custom: map[string]any{"icon": "🥞"},
})
if err != nil {
  log.Fatal(err)
}

// Delete the folder (and all bookmarks in it)
_, err = client.Feeds().DeleteBookmarkFolder(context.Background(), updateResp.Data.BookmarkFolder.ID)
if err != nil {
  log.Fatal(err)
}
```

```java label="Java"
// Add a bookmark with a new folder
AddBookmarkResponse addResponse = feeds.addBookmark(activityId,
    AddBookmarkRequest.builder()
        .userID(testUserId)
        .newFolder(AddFolderRequest.builder()
            .name("Breakfast recipes")
            .custom(Map.of("icon", "🍳"))
            .build())
        .build()).execute().getData();

String folderId = addResponse.getBookmark().getFolder().getId();

// Update the folder
UpdateBookmarkFolderResponse updateResponse = feeds.updateBookmarkFolder(folderId,
    UpdateBookmarkFolderRequest.builder()
        .name("Sweet Breakfast Recipes")
        .custom(Map.of("icon", "🥞"))
        .build()).execute().getData();

// Delete the folder (and all bookmarks in it)
feeds.deleteBookmarkFolder(updateResponse.getBookmarkFolder().getId()).execute();
```

```php label="php"
// Add a bookmark with a new folder
$addResponse = $feedsClient->addBookmark(
    $activityId,
    new GeneratedModels\AddBookmarkRequest(
        userID: 'user_123',
        newFolder: new GeneratedModels\AddFolderRequest(
            name: 'Breakfast recipes',
            custom: (object)['icon' => '🍳']
        )
    )
);
$folderId = $addResponse->getData()->bookmark->folder->id;

// Update the folder
$updateResponse = $feedsClient->updateBookmarkFolder(
    $folderId,
    new GeneratedModels\UpdateBookmarkFolderRequest(
        name: 'Sweet Breakfast Recipes',
        custom: (object)['icon' => '🥞']
    )
);

// Delete the folder (and all bookmarks in it)
$feedsClient->deleteBookmarkFolder($updateResponse->getData()->bookmarkFolder->id);
```

```csharp label="C#"
// Add a bookmark with a new folder
var addResponse = await _feedsV3Client.AddBookmarkAsync(
    activityId,
    new AddBookmarkRequest
    {
        UserID = _testUserId,
        NewFolder = new AddFolderRequest
        {
            Name = "Breakfast recipes",
            Custom = new Dictionary<string, object> { ["icon"] = "🍳" }
        }
    }
);
var folderId = addResponse.Bookmark.Folder.Id;

// Update the folder
var updateResponse = await _feedsV3Client.UpdateBookmarkFolderAsync(
    folderId,
    new UpdateBookmarkFolderRequest
    {
        Name = "Sweet Breakfast Recipes",
        Custom = new Dictionary<string, object> { ["icon"] = "🥞" }
    }
);

// Delete the folder (and all bookmarks in it)
await _feedsV3Client.DeleteBookmarkFolderAsync(updateResponse.BookmarkFolder.Id);
```

```python label="Python"
# Add a bookmark with a new folder
add_response = self.client.feeds.add_bookmark(
    activity_id,
    user_id=self.test_user_id,
    new_folder=AddFolderRequest(
        name="Breakfast recipes",
        custom={"icon": "🍳"},
    ),
)
folder_id = add_response.data.bookmark.folder.id

# Update the folder
update_response = self.client.feeds.update_bookmark_folder(
    folder_id,
    name="Sweet Breakfast Recipes",
    custom={"icon": "🥞"},
)

# Delete the folder (and all bookmarks in it)
self.client.feeds.delete_bookmark_folder(update_response.data.bookmark_folder.id)
```

```ruby label="Ruby"
# Add a bookmark with a new folder
add_response = client.feeds.add_bookmark(
  activity_id,
  GetStream::Generated::Models::AddBookmarkRequest.new(
    user_id: 'user123',
    new_folder: GetStream::Generated::Models::AddFolderRequest.new(
      name: 'Breakfast recipes',
      custom: { icon: '🍳' }
    )
  )
)
folder_id = add_response.bookmark.folder.id

# Update the folder
update_response = client.feeds.update_bookmark_folder(
  folder_id,
  GetStream::Generated::Models::UpdateBookmarkFolderRequest.new(
    name: 'Sweet Breakfast Recipes',
    custom: { icon: '🥞' }
  )
)

# Delete the folder (and all bookmarks in it)
client.feeds.delete_bookmark_folder(update_response.bookmark_folder.id)
```

</Tabs>


---

This page was last updated at 2026-04-22T16:42:42.085Z.

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/).