Official Ruby SDK for GetStream's activity feeds and chat APIs.
Add this line to your application's Gemfile:
gem 'getstream-ruby'And then execute:
$ bundle installOr install it yourself as:
$ gem install getstream-rubyIf you are currently using stream-chat-ruby, we have a detailed migration guide with side-by-side code examples for common Chat use cases. See the Migration Guide.
require 'getstream_ruby'
client = GetStreamRuby.manual(
api_key: "your_api_key",
api_secret: "your_api_secret",
# Optional HTTP tuning for keep-alive / connection reuse
connection_keep_alive: true,
# Optional: bring your own Faraday adapter (default is Faraday.default_adapter)
faraday_adapter: :net_http,
faraday_adapter_options: {
# adapter-specific options
}
)You can also set these via environment variables:
STREAM_CONNECTION_KEEP_ALIVE=true
STREAM_FARADAY_ADAPTER=net_httpCreate a .env file in your project root:
# Copy the example file
cp env.example .env
# Edit .env with your actual credentials
STREAM_API_KEY=your_api_key
STREAM_API_SECRET=your_api_secretrequire 'getstream_ruby'
# Uses .env file automatically
client = GetStreamRuby.env
# or
client = GetStreamRuby.client # defaults to .envexport STREAM_API_KEY=your_api_key
export STREAM_API_SECRET=your_api_secretrequire 'getstream_ruby'
client = GetStreamRuby.env_vars# Create a client instance
client = GetStreamRuby.client
# Or create with custom configuration
client = GetStreamRuby::Client.new(config)# Create a user feed
feed_response = client.feed.create("user", "123", {
name: "John Doe",
email: "[email protected]"
})# Add an activity
activity_response = client.feed.add_activity("user", "123", {
actor: "user:123",
verb: "post",
object: "post:456",
message: "Hello, world!",
published: Time.now.iso8601
})# Get activities from a feed
activities = client.feed.get_activities("user", "123", {
limit: 10,
offset: 0
})# Follow another user
follow_response = client.feed.follow("user:123", "user:456", {
activity_copy_limit: 5
})
# Unfollow a user
unfollow_response = client.feed.unfollow("user:123", "user:456")The SDK provides specific error classes for different types of errors:
begin
client.feed.create("user", "123")
rescue GetStreamRuby::AuthenticationError => e
puts "Authentication failed: #{e.message}"
rescue GetStreamRuby::ValidationError => e
puts "Validation error: #{e.message}"
rescue GetStreamRuby::APIError => e
puts "API error: #{e.message}"
endRetries are opt-in via retry_config: and disabled by default (the client makes exactly one attempt; errors surface unchanged). When enabled, only GET/HEAD requests are retried, and only when they fail with HTTP 429 (unless the error is marked unrecoverable) or a transport-level error (connection reset, timeout, DNS failure, TLS handshake failure). Writes, 5xx responses, and other 4xx responses are never retried.
client = GetStreamRuby::Client.new(
api_key: '...', api_secret: '...',
retry_config: GetStreamRuby::RetryConfig.new(enabled: true, max_attempts: 3, max_backoff: 30.0)
)max_attempts caps the total number of attempts (default 3). max_backoff caps the wait between attempts (default 30.0 seconds). A 429 with a Retry-After header waits exactly that long, clamped to max_backoff, with no jitter. Otherwise the wait is full jitter: a random delay between 0 and min(max_backoff, 2**attempt) seconds.
Pass a stdlib Logger via logger: to get structured, single-line log events. With no logger:, the SDK produces zero output; the SDK never sets the logger's level either, that's the caller's call.
require 'logger'
client = GetStreamRuby.manual(
api_key: "your_api_key",
api_secret: "your_api_secret",
logger: Logger.new($stdout)
)Four events are emitted:
client.initialized(INFO, once at construction): SDK version and the effective client config (pool size, timeouts, gzip, whether a customhttp_client/log_bodiesis set).http.request.sent(DEBUG, before each request).http.response.received(DEBUG, after any response including 4xx/5xx — those are just data, not a failure).http.request.failed(ERROR, transport failure only: no HTTP response was received at all, e.g. connection reset, timeout, DNS failure, TLS handshake failure). When retries are enabled, each retried attempt also emitshttp.request.failedat DEBUG with aretry.attemptfield (1-indexed) before its backoff sleep; a 429 retry omitserror.type(the pairedhttp.response.receivedalready recorded the status), a transport-error retry includes it.
Query values for api_key/api_secret/token are always redacted to <redacted>, and the same keys are redacted (shallowly, top-level only) in JSON body logging. No headers are ever logged. Request/response bodies are not logged by default; pass log_bodies: true to opt in (values for the keys above are still redacted). Enabling it emits one WARN at construction as a reminder that your logs will now contain body content.
# Clone the repository
git clone https://github.com/getstream/getstream-ruby.git
cd getstream-ruby
# Setup development environment
make dev-setup
# Run all checks
make dev-checkgetstream_ruby/
├── lib/getstream_ruby/ # Main SDK code
├── spec/ # Test files
│ ├── integration/ # Integration tests
│ └── *.rb # Unit tests
├── .github/workflows/ # CI/CD workflows
├── .rubocop.yml # Code style configuration
├── .env.example # Environment template
├── Makefile # Development commands
├── Rakefile # Ruby task runner
└── Gemfile # Dependencies
This project includes a simple Makefile with essential commands:
make install # Install dependencies
make setup # Setup development environment
make dev-setup # Complete development setupmake test # Run unit tests only
make test-integration # Run integration tests only
make test-all # Run all tests (unit + integration)make format # Auto-format code with RuboCop
make format-check # Check formatting (CI-friendly)
make lint # Run RuboCop linter
make security # Run security audit
make dev-check # Run all development checksmake clean # Clean up generated files
make console # Start IRB console with SDK loaded
make version # Show current version
make help # Show all available commands-
Copy environment template:
cp .env.example .env
-
Edit
.envwith your GetStream credentials:STREAM_API_KEY=your_api_key STREAM_API_SECRET=your_api_secret
-
Run tests:
make test-all
This project supports Ruby 2.6+ and uses the default bundler version for simplicity.
Requirements:
- Ruby 2.6.0+ (see
.ruby-version) - Bundler (latest compatible version)
This project uses RuboCop for code style enforcement. The configuration is in .rubocop.yml.
- Auto-fix issues:
make format-fix - Check style:
make format-check - View all issues:
make lint
The project includes several development tools configured and ready to use:
- RuboCop - Code style and quality enforcement
- RSpec - Testing framework
- SimpleCov - Code coverage reporting
- YARD - Documentation generation
- Bundler Audit - Security vulnerability scanning
- WebMock - HTTP request mocking (disabled for integration tests)
Run make help to see all available commands, or check the sections above for categorized commands.
Integration tests require valid GetStream API credentials. They test real API interactions:
# Run integration tests (requires .env file)
make test-integration
# Run specific integration test
bundle exec rspec spec/integration/feed_integration_spec.rb
bundle exec rspec spec/integration/moderation_integration_spec.rbThe project includes simple GitHub Actions workflows:
-
CI Pipeline: Runs on every push and pull request
- Unit tests
- Code formatting checks
- Security audit
- Integration tests (on master/main branches only)
-
Release Pipeline: Manual releases via git tags
- Create a tag:
git tag v1.0.0 && git push origin v1.0.0 - Automated gem build and release
- Create a tag:
-
Pre-releasee Pipeline: Create a pre-release to trigger the workflow
- Push a tag (e.g.
1.0.0.beta.1), then go to GitHub Releases -> Draft a new release, select the tag, check "Set as a pre-release", and publish. The CI job will trigger automatically and publish the package.
- Push a tag (e.g.
To enable integration tests in CI, configure these GitHub repository settings:
-
Create a "ci" environment:
- Go to Settings → Environments
- Click "New environment"
- Name it "ci"
-
Configure environment variables:
- In the "ci" environment, go to Environment variables
- Add:
STREAM_API_KEY= your GetStream API key
-
Configure environment secrets:
- In the "ci" environment, go to Environment secrets
- Add:
STREAM_API_SECRET= your GetStream API secret
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes
- Run tests:
make dev-check - Commit with conventional messages:
git commit -m "feat: add new feature" - Push and create a pull request
Commit Message Format:
feat:- New featuresfix:- Bug fixesdocs:- Documentation changesstyle:- Code style changesrefactor:- Code refactoringtest:- Test changeschore:- Maintenance tasks
Bug reports and pull requests are welcome on GitHub at https://github.com/getstream/getstream-ruby.
Releases are driven by release-please.
- Merge PRs to
masterwith conventional-commit titles, using Squash and merge. The title becomes the commit subject and decides the next version:feat:is a minor,fix:andperf:are a patch,feat!:or<type>(scope)!:is a major. Other types (chore,ci,docs,test,refactor) ship nothing. - Squashing is a convention here, not yet enforced. The repo still has
allow_merge_commit: true,allow_rebase_merge: trueandsquash_merge_commit_title: COMMIT_OR_PR_TITLE, and until someone with admin sets those tofalse,falseandPR_TITLE(as getstream-go has), two things silently skip a release: a merge commit, whose subject is not conventional and whose body only yields a plainfeat:/fix:prefix, neverfeat!:; and a single-commit PR, which squashes to that commit's subject rather than the PR title.pr_title.ymlonly checks the PR title field, so it passes in both cases. - release-please keeps a Release PR open with the version bump in
lib/getstream_ruby/version.rbandCHANGELOG.md. It is opened bygithub-actions[bot], so approve it and run its held checks like any other PR. Never edit the version by hand. - Merging the Release PR runs
make format-check,make lint,make security,make testand the four integration suites (chat, feed, video, GCP load balancer) on that merge commit, which is the commit the tag will point at. Only if that is green does the workflow create the tag and the GitHub Release and push the gem to RubyGems. The order matters: a tag, a GitHub Release and a gem push cannot be withdrawn, a failed push can be retried.
If the suite goes red after the Release PR merged, the release stays pending and every
later push to master logs a warning naming the commit to go back to, rather than
failing. Recovery in both that case and a failed gem push is "Re-run failed jobs" on the
run for that merge commit. Once GitHub has retired the run, dispatch Release from master
with publish_tag set to the tag (for example v12.1.1), which builds and pushes that
tag without touching release-please.
To force a specific version, type Release-As: X.Y.Z in the commit message box of the
squash dialog when merging a PR; the PR description is not copied there. To hotfix while
master carries unreleased work, branch N.x from the last tag, cherry-pick the fix,
and merge the Release PR that release-please opens against that branch.
last-release-sha in release-please-config.json is temporary. v12.1.0 sits on a bump
commit the previous workflow created off-branch and never pushed, so release-please
cannot reach it by walking master and would otherwise treat the whole history as
unreleased. Delete the key once a release-please-created release exists on master; the
walk stops at that release commit before it reaches the pin.
The gem is available as open source under the terms of the MIT License.