// Start the export task
const response = await client.feeds.exportFeedUserData({
user_id: userToExport.id,
});
// You have to poll this endpoint
const taskResponse = await client.getTask({ id: response.task_id });
console.log(taskResponse.status === "completed");GDPR
Companies conducting business within the European Union are legally required to comply with the General Data Protection Regulation (GDPR).
While many aspects of this regulation may not significantly affect your integration with Stream, the GDPR provisions regarding the right to data access and the right to erasure are directly pertinent.
These provisions relate to data that is stored and managed on Stream’s servers.
The Right to Access Data
GDPR gives EU citizens the right to request access to their information and the right to have access to this information in a portable format. Stream covers this requirement with the export method.
The Feeds export method will export the following data where the user id the owner:
- User data
- Feeds
- Follows
- Activities
- Comments
- Reactions
- Bookmarks
- Bookmark folders
- Collections
This method can only be used with server-side authentication:
// Start the export task
response, err := client.Feeds().ExportFeedUserData(context.Background(), &getstream.ExportFeedUserDataRequest{
UserID: userToExport.ID,
})
if err != nil {
log.Fatal(err)
}
// You have to poll this endpoint
taskResponse, err := client.GetTask(context.Background(), response.Data.TaskID, &getstream.GetTaskRequest{})
if err != nil {
log.Fatal(err)
}
fmt.Println(taskResponse.Data.Status == "completed")// Start the export task
ExportFeedUserDataResponse response = feeds.exportFeedUserData(
ExportFeedUserDataRequest.builder()
.userID(userToExport.getId())
.build()
).execute().getData();
// You have to poll this endpoint
var taskResponse = client.getTask(response.getTaskId()).execute().getData();
System.out.println("completed".equals(taskResponse.getStatus()));// Start the export task
$response = $feedsClient->exportFeedUserData(
new GeneratedModels\ExportFeedUserDataRequest(
userID: $userToExport->id
)
);
// You have to poll this endpoint
$taskResponse = $client->getTask($response->getData()->taskID);
echo $taskResponse->getData()->status === 'completed';// Start the export task
var response = await _feedsV3Client.ExportFeedUserDataAsync(
new ExportFeedUserDataRequest { UserID = userToExport.ID }
);
// You have to poll this endpoint
var taskResponse = await _client.GetTaskAsync(response.TaskID);
Console.WriteLine(taskResponse.Status == "completed");# Start the export task
response = client.feeds.export_feed_user_data(user_id=user_to_export.id)
# You have to poll this endpoint
task_response = client.get_task(response.task_id)
print(task_response.status == "completed")# Start the export task
response = client.feeds.export_feed_user_data(
GetStream::Generated::Models::ExportFeedUserDataRequest.new(
user_id: user_to_export.id
)
)
# You have to poll this endpoint
task_response = client.get_task(response.data.task_id)
puts task_response.data.status == 'completed'Accessing the exported data
You can check the status of an export request using the task ID returned when the task was created. The result of the task contains the URL to the JSON file.
The URL to the export file has an expiration of 24-hours. The link is generated every time you request the export status. The export will be available for 60 days.
const response = await client.getTask({ id: response.task_id });
if (response.status === "completed") {
console.log(response.result.url);
}resp, err := client.GetTask(taskID)
if err != nil {
return err
}
if resp.Status == "completed" {
fmt.Println(resp.Result["url"])
}var taskStatusResponse = TaskStatus.get(taskId).request();
// "completed".equals(taskStatusResponse.status);$response = $client->getTask($response["task_id"]);
if ($response["status"] == "completed") {
echo $response["result"]["url"];
};var taskStatus = await taskClient.GetTaskStatusAsync(taskId);
if (taskStatus.Status == AsyncTaskStatus.Completed)
{
var exportedFileUrl = taskStatus.Result.Values.First().ToString();
}response = client.get_task(response["task_id"])
if response['status'] == 'completed':
print(response['result']['url'])response = client.get_task(response["task_id"])
if response['status'] == 'completed'
puts(response['result']['url'])The Right to Erasure
The GDPR also grants EU citizens the right to request the deletion of their personal information. Stream offers mechanisms to delete users and feeds data in accordance with various use cases, ensuring compliance with these regulations.
The following data will be deleted:
- Follows where the user is owner of either source or target feed
- Feeds owned by the user - will follow the logic for deleting feeds as described here
- Activities owned by the user
- Comments owned by the user
- Reactions owned by the user
- Bookmarks owned by the user
- Bookmark folders owned by the user
- Collections owned by the user
NOTE: This does not delete the user’s account, only their Feeds data. If you want to delete the user please refer to deleting a user
Deleting user data is an irreversible operation. This goes for both soft and hard deletes.
// Start the delete task
const response = await serverClient.feeds.deleteFeedUserData({
user_id: userToDelete.id,
hard_delete: false,
});
// You have to poll this endpoint
const taskResponse = await client.getTask({ id: response.task_id });
console.log(taskResponse.status === "completed");// Start the delete task
response, err := client.Feeds().DeleteFeedUserData(context.Background(), &getstream.DeleteFeedUserDataRequest{
UserID: userToDelete.ID,
HardDelete: getstream.PtrTo(false),
})
if err != nil {
log.Fatal(err)
}
// You have to poll this endpoint
taskResponse, err := client.GetTask(context.Background(), response.Data.TaskID, &getstream.GetTaskRequest{})
if err != nil {
log.Fatal(err)
}
fmt.Println(taskResponse.Data.Status == "completed")// Start the delete task
DeleteFeedUserDataResponse response = feeds.deleteFeedUserData(
DeleteFeedUserDataRequest.builder()
.userID(userToDelete.getId())
.hardDelete(false)
.build()
).execute().getData();
// You have to poll this endpoint
var taskResponse = client.getTask(response.getTaskId()).execute().getData();
System.out.println("completed".equals(taskResponse.getStatus()));// Start the delete task
$response = $feedsClient->deleteFeedUserData(
new GeneratedModels\DeleteFeedUserDataRequest(
userID: $userToDelete->id,
hardDelete: false
)
);
// You have to poll this endpoint
$taskResponse = $client->getTask($response->getData()->taskID);
echo $taskResponse->getData()->status === 'completed';// Start the delete task
var response = await _feedsV3Client.DeleteFeedUserDataAsync(
new DeleteFeedUserDataRequest
{
UserID = userToDelete.ID,
HardDelete = false
}
);
// You have to poll this endpoint
var taskResponse = await _client.GetTaskAsync(response.TaskID);
Console.WriteLine(taskResponse.Status == "completed");# Start the delete task
response = client.feeds.delete_feed_user_data(
user_id=user_to_delete.id,
hard_delete=False
)
# You have to poll this endpoint
task_response = client.get_task(response.task_id)
print(task_response.status == "completed")# Start the delete task
response = client.feeds.delete_feed_user_data(
GetStream::Generated::Models::DeleteFeedUserDataRequest.new(
user_id: user_to_delete.id,
hard_delete: false
)
)
# You have to poll this endpoint
task_response = client.get_task(response.data.task_id)
puts task_response.data.status == 'completed'Deleting a user
client.deleteUsers({ user_ids: ["<id>"] });
//restore
client.restoreUsers({ user_ids: ["<id>"] });// Delete users
deleteRequest := &getstream.DeleteUsersRequest{
UserIds: []string{"<id>"},
}
_, err = client.DeleteUsers(context.Background(), deleteRequest)
// Restore users
restoreRequest := &getstream.RestoreUsersRequest{
UserIds: []string{"<id>"},
}
_, err = client.RestoreUsers(context.Background(), restoreRequest)// Delete users
client.deleteUsers(
DeleteUsersRequest.builder()
.userIds(Arrays.asList("<id>"))
.build()
).execute();
// Restore users
client.restoreUsers(
RestoreUsersRequest.builder()
.userIds(Arrays.asList("<id>"))
.build()
).execute();// Delete users (soft delete by default)
$client->deleteUsers(
new GeneratedModels\DeleteUsersRequest(
userIds: ['<id>']
)
);
// Delete users with options (hard delete)
$client->deleteUsers(
new GeneratedModels\DeleteUsersRequest(
userIds: ['<id>'],
user: 'hard',
messages: 'hard',
conversations: 'hard',
newChannelOwnerID: 'new-owner-id'
)
);
// Restore users
$client->restoreUsers(
new GeneratedModels\RestoreUsersRequest(
userIds: ['<id>']
)
);// Delete users
await _client.DeleteUsersAsync(new DeleteUsersRequest
{
UserIds = new List<string> { "<id>" }
});
// Restore users
await _client.RestoreUsersAsync(new RestoreUsersRequest
{
UserIds = new List<string> { "<id>" }
});# Delete users
client.delete_users(user_ids=["<id>"])
# Restore users
client.restore_users(user_ids=["<id>"])# Delete users
client.delete_users(
GetStream::Generated::Models::DeleteUsersRequest.new(
user_ids: ['<id>']
)
)
# Restore users
client.restore_users(
GetStream::Generated::Models::RestoreUsersRequest.new(
user_ids: ['<id>']
)
)The delete users endpoints supports the following parameters to control which data needs to be deleted and how. By default users and their data are soft-deleted.
| Name | Type | Description | Optional |
|---|---|---|---|
user | Enum (soft, pruning, hard) | - Soft: marks user as deleted and retains all user data. - Pruning: marks user as deleted and nullifies user information. - Hard: deletes user completely - this requires hard option for messages and conversation as well. | Yes |
conversations | Enum (soft, hard) | - Soft: marks all conversation channels as deleted (same effect as Delete Channels with ‘hard’ option disabled). - Hard: deletes channel and all its data completely including messages (same effect as Delete Channels with ‘hard’ option enabled). | Yes |
messages | Enum (soft, pruning, hard) | - Soft: marks all user messages as deleted without removing any related message data. - Pruning: marks all user messages as deleted, nullifies message information and removes some message data such as reactions and flags. - Hard: deletes messages completely with all related information. | Yes |
new_channel_owner_id | string | Channels owned by hard-deleted users will be transferred to this userID. If you doesn’t provide a value, the channel owner will have a system generated ID like delete-user-8219f6578a7395g | Yes |
calls | Enum (soft, hard) | - Soft: marks calls and related data as deleted. - Hard: deletes calls and related data completely Note that this applies only to 1:1 calls, not group calls | Yes |
Deleting users in bulk can take some time, this is how you can check the progress:
// Example of monitoring the status of an async task
// The logic is same for all async tasks
const response = _; // Result of a Stream async API request
// You need to poll this endpoint
const taskResponse = await client.getTask({ id: response.task_id });
console.log(taskResponse.status === "completed");// Example of monitoring the status of an async task
// The logic is same for all async tasks
response, err := _ // Result of a Stream async API request
if err != nil {
log.Fatal(err)
}
// You need to poll this endpoint
taskResponse, err := client.GetTask(context.Background(), response.Data.TaskID, &getstream.GetTaskRequest{})
if err != nil {
log.Fatal(err)
}
fmt.Println(taskResponse.Data.Status == "completed")// Example of monitoring the status of an async task
// The logic is same for all async tasks
var response = _ // Result of a Stream async API request
// You need to poll this endpoint
var taskResponse = client.getTask(response.getTaskId()).execute().getData();
System.out.println("completed".equals(taskResponse.getStatus()));// Example of monitoring the status of an async task
// The logic is same for all async tasks
$response = _ // Result of a Stream async API request
$taskId = $response->getData()->taskID;
// you need to poll this endpoint
$taskResponse = $client->getTask($taskId);
echo $taskResponse->getData()->status === 'completed';// Example of monitoring the status of an async task
// The logic is same for all async tasks
var response = _ // Result of a Stream async API request
// You need to poll this endpoint
var taskResponse = await _client.GetTaskAsync(response.TaskID);
Console.WriteLine(taskResponse.Status == "completed");# Example of monitoring the status of an async task
# The logic is same for all async tasks
response = _ # Result of a Stream async API request
# You need to poll this endpoint
task_response = client.get_task(response.task_id)
print(task_response.status == "completed")# Example of monitoring the status of an async task
# The logic is same for all async tasks
response = _ # Result of a Stream async API request
# You need to poll this endpoint
task_response = client.get_task(response.data.task_id)
puts task_response.data.status == 'completed'