Skip to content

Import Files

Info:

Imports are not entirely supported on V3. This page is a work in progress.

If you've just started using Stream, you might want to import data from your old infrastructure. Instead of using the APIs and creating your own import scripts, you can make use of our import feature.

Import files use the JSON Lines format (one JSON object per line). Each line is an envelope that wraps a single record:

{ "type": "<entity>", "data": { ... } }

Valid values for type are: user, feed, feed_group, feed_view, activity, comment, reaction, bookmark, follow, collection, poll, and poll_vote. The full JSON Schemas are published at GetStream/protocol.

The Process

The steps for importing data into your app are as follows:

Install the Stream CLI

curl -fsSL https://getstream.io/cli.sh | bash

Set up your app

getstream login
getstream init

Upload the file and track the import task

getstream import feeds myfile.jsonl --watch
getstream import status <task-id>
getstream import list

See the getstream import reference for all flags.

Users

Users are shared with chat and video. So if you already use those products you typically don't need to import users. The structure for importing users is shown below:

{ "type": "user", "data": { "id": "myuserid", "role": "user", "custom": {} } }

Feeds

This is how you can import feeds.

{
  "type": "feed",
  "data": {
    "group_id": "user",
    "id": "myuserid",
    "fid": "user:myuserid",
    "created_by_id": "myuserid",
    "name": "My Feed",
    "description": "A sample feed",
    "visibility": "public",
    "custom": {}
  }
}

fid is the fully-qualified feed id and is typically "{group_id}:{id}".

Follows

For follows specify the import in the following structure:

{
  "type": "follow",
  "data": {
    "source_fid": "timeline:123",
    "target_fid": "user:222",
    "source_created_by_id": "myuserid",
    "target_created_by_id": "user222",
    "push_preference": "none",
    "custom": {}
  }
}

source_created_by_id and target_created_by_id are the user IDs who created the source and target feeds, respectively. They're required for import (the live Follow API call doesn't need them, since it derives the creator from each feed automatically).

Activities

Activities are the core records posted to one or more feeds:

{
  "type": "activity",
  "data": {
    "id": "activity-123",
    "type": "post",
    "user_id": "user-222",
    "fids": ["user:myuserid"],
    "text": "hello world",
    "visibility": "public",
    "custom": {}
  }
}

Comments

For comments specify the import in the following structure:

{
  "type": "comment",
  "data": {
    "id": "comment-1",
    "object_type": "activity",
    "object_id": "activity-123",
    "user_id": "user-222",
    "text": "buy a gaming chair",
    "mentioned_user_ids": ["user-222"],
    "parent_id": null,
    "attachments": [],
    "custom": {}
  }
}

Reactions

For reactions specify the import in the following structure:

{
  "type": "reaction",
  "data": {
    "user_id": "user-222",
    "activity_id": "activity-123",
    "type": "like",
    "custom": {}
  }
}

activity_id is required. Set comment_id as well when reacting to a comment on the activity.

Polls

Polls are a shared entity — the same poll and poll_vote records are used by both Feeds and Chat. To attach a poll to an activity, import the poll first, then reference it from the activity via poll_id:

{
  "type": "poll",
  "data": {
    "id": "poll-123",
    "name": "Which feature should we build next?",
    "created_by_id": "user-222",
    "voting_visibility": "public",
    "enforce_unique_vote": true,
    "max_votes_allowed": 1,
    "options": [
      { "id": "option-1", "text": "Stories" },
      { "id": "option-2", "text": "Live video" },
      { "id": "option-3", "text": "Polls" }
    ],
    "custom": {}
  }
}

The poll fields are:

name type description required
id string unique poll ID (max 255 chars)
name string the poll question / title
created_by_id string user ID of the poll creator
description string poll description
voting_visibility string public or anonymous (defaults to public)
enforce_unique_vote boolean only allow a single vote per user
max_votes_allowed integer maximum votes per user, between 1 and 10
allow_user_suggested_options boolean allow users to suggest new options
allow_answers boolean allow free-form text answers
is_closed boolean whether the poll is closed for voting
options array poll options, each with an id (required), text, and custom
created_at string creation time (defaults to import time)
updated_at string last update time (defaults to created_at)
custom object custom fields (up to 5 KiB)

To attach the poll to an activity, set poll_id:

{
  "type": "activity",
  "data": {
    "id": "activity-123",
    "type": "poll",
    "user_id": "user-222",
    "fids": ["user:myuserid"],
    "poll_id": "poll-123",
    "custom": {}
  }
}

Poll Votes

A poll_vote is either a vote (pointing at an option via option_id) or an answer (free-form text via answer_text). The two are mutually exclusive — set is_answer to true with answer_text for an answer, otherwise provide option_id for a vote. Import votes after their poll.

{
  "type": "poll_vote",
  "data": {
    "id": "vote-1",
    "poll_id": "poll-123",
    "option_id": "option-1",
    "user_id": "user-222",
    "custom": {}
  }
}

The poll_vote fields are:

name type description required
id string unique poll vote ID (max 255 chars)
poll_id string ID of the poll this vote belongs to
user_id string user ID who cast the vote
option_id string ID of the chosen option (required for a vote, omit for an answer)
is_answer boolean set to true when this is a free-form answer
answer_text string the free-form answer text (required when is_answer is true)
created_at string creation time (defaults to import time)
updated_at string last update time (defaults to created_at)

Putting it all together

A single import file mixes entity types — one record per line:

{"type":"user","data":{"id":"myuserid","role":"user","custom":{}}}
{"type":"feed","data":{"group_id":"user","id":"myuserid","fid":"user:myuserid","created_by_id":"myuserid","custom":{}}}
{"type":"activity","data":{"id":"activity-123","type":"post","user_id":"myuserid","fids":["user:myuserid"],"text":"hello world"}}
{"type":"comment","data":{"id":"comment-1","object_type":"activity","object_id":"activity-123","user_id":"myuserid","text":"nice!"}}
{"type":"reaction","data":{"user_id":"myuserid","activity_id":"activity-123","type":"like"}}
{"type":"poll","data":{"id":"poll-123","name":"Which feature next?","created_by_id":"myuserid","options":[{"id":"option-1","text":"Stories"},{"id":"option-2","text":"Polls"}]}}
{"type":"activity","data":{"id":"activity-456","type":"poll","user_id":"myuserid","fids":["user:myuserid"],"poll_id":"poll-123"}}
{"type":"poll_vote","data":{"id":"vote-1","poll_id":"poll-123","option_id":"option-1","user_id":"myuserid"}}