diff --git a/apps/public/content/docs/(tracking)/sdks/index.mdx b/apps/public/content/docs/(tracking)/sdks/index.mdx
index c6ca11be..5bffc11b 100644
--- a/apps/public/content/docs/(tracking)/sdks/index.mdx
+++ b/apps/public/content/docs/(tracking)/sdks/index.mdx
@@ -81,6 +81,16 @@ For most web projects, we recommend starting with one of these:
- ✅ Async support
- ✅ Django and Flask compatible
+- **[Rust](/docs/sdks/rust)** - Rust SDK for server-side tracking
+ - ✅ Async/await support
+ - ✅ Type-safe API
+ - ✅ Environment variable configuration
+
+- **[Ruby](/docs/sdks/ruby)** - Ruby SDK for server-side tracking
+ - ✅ Rails integration
+ - ✅ Gem-based installation
+ - ✅ Simple API
+
## Mobile SDKs
- **[React Native](/docs/sdks/react-native)** - Cross-platform mobile analytics
@@ -108,7 +118,7 @@ Not sure which SDK to use? Here are some recommendations:
- **Static website or HTML?** → Use [Script Tag](/docs/sdks/script)
- **React app?** → Use [Web SDK](/docs/sdks/web) or [Script Tag](/docs/sdks/script)
- **Next.js app?** → Use [Next.js SDK](/docs/sdks/nextjs)
-- **Server-side tracking?** → Use [Python](/docs/sdks/python) or [Node](/docs/sdks/javascript)
+- **Server-side tracking?** → Use [Python](/docs/sdks/python), [Rust](/docs/sdks/rust), [Ruby](/docs/sdks/ruby), or [Node](/docs/sdks/javascript)
- **Mobile app?** → Use [React Native](/docs/sdks/react-native), [Swift](/docs/sdks/swift), or [Kotlin](/docs/sdks/kotlin)
diff --git a/apps/public/content/docs/(tracking)/sdks/meta.json b/apps/public/content/docs/(tracking)/sdks/meta.json
index 9e414baf..46af77e4 100644
--- a/apps/public/content/docs/(tracking)/sdks/meta.json
+++ b/apps/public/content/docs/(tracking)/sdks/meta.json
@@ -11,6 +11,8 @@
"remix",
"express",
"python",
+ "rust",
+ "ruby",
"react-native",
"swift",
"kotlin",
diff --git a/apps/public/content/docs/(tracking)/sdks/ruby.mdx b/apps/public/content/docs/(tracking)/sdks/ruby.mdx
new file mode 100644
index 00000000..16fff43f
--- /dev/null
+++ b/apps/public/content/docs/(tracking)/sdks/ruby.mdx
@@ -0,0 +1,218 @@
+---
+title: Ruby
+---
+
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+import { Callout } from 'fumadocs-ui/components/callout';
+import CommonSdkConfig from '@/components/common-sdk-config.mdx';
+
+The OpenPanel Ruby SDK allows you to track user behavior in your Ruby applications. This guide provides instructions for installing and using the Ruby SDK in your project.
+
+
+View the [Ruby SDK on GitHub](https://github.com/tstaetter/openpanel-ruby-sdk) for the latest updates and source code.
+
+
+## Installation
+
+
+### Install dependencies
+
+If you're using Bundler, add to your `Gemfile`:
+
+```bash
+bundle add openpanel-sdk
+```
+
+Or install the gem directly:
+
+```bash
+gem install openpanel-sdk
+```
+
+### Set environment variables
+
+Set your environment variables in a `.env` file:
+
+```bash
+OPENPANEL_TRACK_URL=https://api.openpanel.dev/track
+OPENPANEL_CLIENT_ID=
+OPENPANEL_CLIENT_SECRET=
+```
+
+### Initialize
+
+Require and initialize the OpenPanel SDK:
+
+```ruby
+require 'openpanel-sdk'
+
+tracker = OpenPanel::SDK::Tracker.new
+```
+
+### Configuration Options
+
+
+
+Additional Ruby-specific options:
+
+- `disabled` - Set to `true` to disable all event tracking
+- `env` - Environment name (e.g., `Rails.env.to_s`)
+
+```ruby
+tracker = OpenPanel::SDK::Tracker.new(
+ { env: Rails.env.to_s },
+ disabled: Rails.env.development?
+)
+```
+
+
+
+## Usage
+
+### Tracking Events
+
+To track an event, use the `track` method:
+
+```ruby
+tracker.track('test_event', payload: { name: 'test' })
+```
+
+### Identifying Users
+
+Create an `IdentifyUser` object and pass it to the `identify` method:
+
+```ruby
+identify_user = OpenPanel::SDK::IdentifyUser.new
+identify_user.profile_id = 'user_123'
+identify_user.email = 'user@example.com'
+identify_user.first_name = 'John'
+identify_user.last_name = 'Doe'
+identify_user.properties = { tier: 'premium', company: 'Acme Inc' }
+
+response = tracker.identify(identify_user)
+```
+
+### Incrementing Properties
+
+To increment a numeric property on a user profile:
+
+```ruby
+tracker.increment_property(identify_user, 'visits', 1)
+```
+
+### Decrementing Properties
+
+To decrement a numeric property on a user profile:
+
+```ruby
+tracker.decrement_property(identify_user, 'credits', 1)
+```
+
+### Filtering Events
+
+Filters are used to prevent sending events to OpenPanel in certain cases. You can filter events by passing a `filter` lambda to the `track` method:
+
+```ruby
+filter = lambda { |payload|
+ # Return true to send the event, false to skip it
+ payload[:name] == 'test'
+}
+
+response = tracker.track('test_event', payload: { name: 'test' }, filter: filter)
+# If filter returns false, response will be nil
+```
+
+## Rails Integration
+
+### Setting up the Tracker
+
+Add the following to your `application_controller.rb`:
+
+```ruby
+before_action :set_openpanel_tracker
+
+protected
+
+def set_openpanel_tracker
+ @openpanel_tracker = OpenPanel::SDK::Tracker.new(
+ { env: Rails.env.to_s },
+ disabled: Rails.env.development?
+ )
+ @openpanel_tracker.set_header 'x-client-ip', request.ip
+ @openpanel_tracker.set_header 'user-agent', request.user_agent
+end
+```
+
+### Tracking Events in Controllers
+
+Use `@openpanel_tracker` in your controllers to track events:
+
+```ruby
+def create
+ @user = User.create(user_params)
+ @openpanel_tracker.track('user_created', payload: { user_id: @user.id })
+ redirect_to @user
+end
+```
+
+### Identifying Users
+
+Create a helper method to convert your app's user model to an `IdentifyUser`:
+
+```ruby
+def identify_user_from_app_user(user, properties: {})
+ iu = OpenPanel::SDK::IdentifyUser.new
+ iu.profile_id = user.id.to_s
+ iu.email = user.email
+ iu.first_name = user.first_name
+ iu.last_name = user.last_name
+ iu.properties = properties
+ iu
+end
+
+# Usage in controller
+def show
+ iu = identify_user_from_app_user(current_user)
+ @openpanel_tracker.identify(iu)
+end
+```
+
+## Advanced Usage
+
+### Setting Custom Headers
+
+You can set custom headers for requests:
+
+```ruby
+tracker.set_header 'x-client-ip', request.ip
+tracker.set_header 'user-agent', request.user_agent
+```
+
+### Error Handling
+
+The SDK returns a `Faraday::Response` object. Check the response status:
+
+```ruby
+response = tracker.track('event', payload: { name: 'test' })
+if response&.status == 200
+ puts 'Event tracked successfully'
+else
+ puts "Failed to track event: #{response&.status}"
+end
+```
+
+### Disabling Tracking
+
+You can disable tracking during initialization or in specific environments:
+
+```ruby
+# Disable during initialization
+tracker = OpenPanel::SDK::Tracker.new({}, disabled: true)
+
+# Or disable in development
+tracker = OpenPanel::SDK::Tracker.new(
+ { env: Rails.env.to_s },
+ disabled: Rails.env.development?
+)
+```
+
diff --git a/apps/public/content/docs/(tracking)/sdks/rust.mdx b/apps/public/content/docs/(tracking)/sdks/rust.mdx
new file mode 100644
index 00000000..0face0d5
--- /dev/null
+++ b/apps/public/content/docs/(tracking)/sdks/rust.mdx
@@ -0,0 +1,204 @@
+---
+title: Rust
+---
+
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+import { Callout } from 'fumadocs-ui/components/callout';
+import CommonSdkConfig from '@/components/common-sdk-config.mdx';
+
+The OpenPanel Rust SDK allows you to track user behavior in your Rust applications. This guide provides instructions for installing and using the Rust SDK in your project.
+
+
+View the [Rust SDK on GitHub](https://github.com/tstaetter/openpanel-rust-sdk/) for the latest updates and source code.
+
+
+## Installation
+
+
+### Install dependencies
+
+Add the following to your `Cargo.toml`:
+
+```toml
+[dependencies]
+openpanel-sdk = "0.1.0"
+```
+
+Or install via cargo:
+
+```bash
+cargo add openpanel-sdk
+```
+
+### Set environment variables
+
+Set your environment variables in a `.env` file:
+
+```bash
+OPENPANEL_TRACK_URL=https://api.openpanel.dev/track
+OPENPANEL_CLIENT_ID=
+OPENPANEL_CLIENT_SECRET=
+```
+
+### Initialize
+
+Import and initialize the OpenPanel SDK:
+
+```rust
+use openpanel_sdk::sdk::Tracker;
+
+let tracker = Tracker::try_new_from_env()?.with_default_headers()?;
+```
+
+### Configuration Options
+
+
+
+
+
+## Usage
+
+### Tracking Events
+
+To track an event, use the `track` method:
+
+```rust
+use std::collections::HashMap;
+use openpanel_sdk::sdk::Tracker;
+
+let mut properties = HashMap::new();
+properties.insert("name".to_string(), "rust".to_string());
+
+let response = tracker
+ .track("test_event".to_string(), Some(properties), None)
+ .await?;
+```
+
+### Identifying Users
+
+To identify a user, you need to convert your user struct into `user::IdentifyUser` by implementing the `From` trait:
+
+```rust
+use std::collections::HashMap;
+use openpanel_sdk::sdk::Tracker;
+use openpanel_sdk::user;
+
+struct Address {
+ pub street: String,
+ pub city: String,
+ pub zip: String,
+}
+
+struct AppUser {
+ pub id: String,
+ pub email: String,
+ pub first_name: String,
+ pub last_name: String,
+ pub address: Address,
+}
+
+impl From
for HashMap {
+ fn from(address: Address) -> Self {
+ let mut properties = HashMap::new();
+ properties.insert("street".to_string(), address.street);
+ properties.insert("city".to_string(), address.city);
+ properties.insert("zip".to_string(), address.zip);
+ properties
+ }
+}
+
+impl From for user::IdentifyUser {
+ fn from(app_user: AppUser) -> Self {
+ Self {
+ profile_id: app_user.id,
+ email: app_user.email,
+ first_name: app_user.first_name,
+ last_name: app_user.last_name,
+ properties: app_user.address.into(),
+ }
+ }
+}
+
+// Usage
+let user = AppUser { /* ... */ };
+let response = tracker.identify(user.into()).await?;
+```
+
+### Incrementing Properties
+
+To increment a numeric property on a user profile:
+
+```rust
+let response = tracker
+ .increment_property(profile_id, "visits", 1)
+ .await?;
+```
+
+### Decrementing Properties
+
+To decrement a numeric property on a user profile:
+
+```rust
+let response = tracker
+ .decrement_property(profile_id, "credits", 1)
+ .await?;
+```
+
+### Filtering Events
+
+Filters are used to prevent sending events to OpenPanel in certain cases. You can filter events by passing a `filter` function to the `track` method:
+
+```rust
+use std::collections::HashMap;
+
+let filter = |properties: HashMap| {
+ // Return true to send the event, false to skip it
+ properties.contains_key("required_key")
+};
+
+let mut properties = HashMap::new();
+properties.insert("name".to_string(), "rust".to_string());
+
+let response = tracker
+ .track("test_event".to_string(), Some(properties), Some(&filter))
+ .await;
+
+// If filter returns false, the event won't be sent and an Err is returned
+match response {
+ Ok(_) => println!("Event sent successfully"),
+ Err(_) => println!("Event was filtered out"),
+}
+```
+
+## Advanced Usage
+
+### Error Handling
+
+The SDK uses Rust's `Result` type for error handling. Always handle errors appropriately:
+
+```rust
+match tracker.track("event".to_string(), Some(properties), None).await {
+ Ok(response) => {
+ if response.status() == 200 {
+ println!("Event tracked successfully");
+ }
+ }
+ Err(e) => {
+ eprintln!("Failed to track event: {}", e);
+ }
+}
+```
+
+### Async Runtime
+
+The SDK uses async/await. Make sure you're running within an async runtime (e.g., Tokio):
+
+```rust
+#[tokio::main]
+async fn main() -> anyhow::Result<()> {
+ let tracker = Tracker::try_new_from_env()?.with_default_headers()?;
+ // ... use tracker
+ Ok(())
+}
+```
+
diff --git a/packages/sdks/_info/frameworks.tsx b/packages/sdks/_info/frameworks.tsx
index e24dd979..e163eac2 100644
--- a/packages/sdks/_info/frameworks.tsx
+++ b/packages/sdks/_info/frameworks.tsx
@@ -11,6 +11,8 @@ import { RemixIcon } from './icons/remix-icon';
import { RestIcon } from './icons/rest-icon';
import { SwiftIcon } from './icons/swift-icon';
import { VueIcon } from './icons/vue-icon';
+import { RustIcon } from './icons/rust-icon';
+import { RubyIcon } from './icons/ruby-icon';
export type Framework = {
key: string;
@@ -98,6 +100,20 @@ export const frameworks: Framework[] = [
href: 'https://github.com/tbleckert/openpanel-laravel/tree/main',
type: ['backend'],
},
+ {
+ key: 'rust',
+ IconComponent: RustIcon,
+ name: 'Rust',
+ href: 'https://openpanel.dev/docs/sdks/rust',
+ type: ['backend'],
+ },
+ {
+ key: 'ruby',
+ IconComponent: RubyIcon,
+ name: 'Ruby',
+ href: 'https://openpanel.dev/docs/sdks/ruby',
+ type: ['backend'],
+ },
{
key: 'ios',
IconComponent: SwiftIcon,
diff --git a/packages/sdks/_info/icons/ruby-icon.tsx b/packages/sdks/_info/icons/ruby-icon.tsx
new file mode 100644
index 00000000..c96d53ac
--- /dev/null
+++ b/packages/sdks/_info/icons/ruby-icon.tsx
@@ -0,0 +1,46 @@
+import type { IconProps } from './types';
+
+export function RubyIcon({ className }: IconProps) {
+ return (
+
+ );
+}
diff --git a/packages/sdks/_info/icons/rust-icon.tsx b/packages/sdks/_info/icons/rust-icon.tsx
new file mode 100644
index 00000000..4e724227
--- /dev/null
+++ b/packages/sdks/_info/icons/rust-icon.tsx
@@ -0,0 +1,17 @@
+import type { IconProps } from './types';
+
+export function RustIcon({ className }: IconProps) {
+ return (
+
+ );
+}