vTilt
Why vTiltHow It WorksFeaturesFAQDocs
Docs / Ruby on Rails
Quick startEvent forwarding
MCP server
Guides
OverviewAuthenticationOAuthAgent skills (prompts)AI intelligenceGoogle Ads
Client setup
CursorClaude DesktopVS CodeCodex
Realtime
Debug ViewRealtime Dashboard
Integration guides
Frontend frameworks
Next.jsNuxt.jsVue.jsReactReact RouterRemixGatsbySvelte / SvelteKitAstroAngularTanStack StartDocusaurus
Backend frameworks
NestJSHonoCloudflare WorkersDjangoFlaskLaravelPhoenixRuby on Rails
Backend languages
PythonPHPRubyElixirGoJava.NET / C#Rust
Stack guides
Vue + PHP
SDK
Browser SDK
InstallScript bundlesEvent trackingAutocaptureIdentify & aliasWeb VitalsSession recordingChat widgetFeature readinessRemote configurationReverse proxyDebug logging
Node SDK
Install & setupCapture, identify & aliasContext & shutdown

Documentation

vTilt
Quick startEvent forwarding

MCP server

Realtime

Debug ViewRealtime Dashboard

Integration guides

NestJSHonoCloudflare WorkersDjangoFlaskLaravelPhoenixRuby on Rails

SDK

DocsIntegration guidesRuby on Rails

Ruby on Rails

Integrate vTilt with Rails — render the SDK in your application layout, identify on every authenticated request, send server-side events from a Net::HTTP helper.

There's no native Ruby SDK yet, but vTilt's wire format is a plain JSON POST so any Ruby HTTP client (Net::HTTP, Faraday, HTTP.rb) can emit events. The pattern below covers rendering the Browser SDK in your Rails layout, identifying the authenticated user on every request, and sending server-side events from a queued job.

#1. Configure credentials

# config/credentials.yml.enc (or environment variables)
vtilt:
  token: { { TOKEN } }
  host: { { ORIGIN } }
yaml
# config/initializers/vtilt.rb
Rails.application.config.vtilt = {
  token: Rails.application.credentials.dig(:vtilt, :token) || ENV.fetch('VTILT_TOKEN'),
  host:  Rails.application.credentials.dig(:vtilt, :host)  || ENV.fetch('VTILT_HOST', 'https://www.vtilt.com'),
}
ruby

#2. Render the SDK in your application layout

<%# app/views/layouts/application.html.erb %>
<!doctype html>
<html lang="en">
<head>
  <script>
    window.__vtilt = <%= {
      token: Rails.application.config.vtilt[:token],
      host:  Rails.application.config.vtilt[:host],
      user:  current_user ? { id: current_user.id.to_s, email: current_user.email } : nil
    }.to_json.html_safe %>;
  </script>
  <script>
    !(function(t,e){/* ...vTilt loader snippet from Quick start... */})(document, window.vt || []);

    vt.init(window.__vtilt.token, {
      api_host: window.__vtilt.host,
      autocapture: true,
      capture_pageview: true,
      capture_pageleave: true,
    });

    if (window.__vtilt.user) {
      vt.identify(window.__vtilt.user.id, { email: window.__vtilt.user.email });
    }
  </script>
</head>
<body><%= yield %></body>
</html>
erb

Important

Important: Identifying users in the application layout means every authenticated page load identifies — not just login. This is the most common bug to avoid; see Identify & alias for the full model.

#3. Server-side capture helper

For events that fire outside a browser session — webhooks, Active Job tasks, server-side conversions — POST directly to vTilt.

# app/services/vtilt.rb
require 'net/http'
require 'json'

class Vtilt
  def self.capture(distinct_id:, event:, properties: {})
    cfg = Rails.application.config.vtilt
    uri = URI.join(cfg[:host], '/api/e')

    Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', open_timeout: 2, read_timeout: 2) do |http|
      req = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
      req.body = {
        api_key: cfg[:token],
        event: event,
        distinct_id: distinct_id,
        properties: properties,
      }.to_json
      http.request(req)
    end
  rescue StandardError => e
    Rails.logger.warn("vtilt capture failed: #{e.message}")
  end
end
ruby
# app/controllers/checkouts_controller.rb
class CheckoutsController < ApplicationController
  def complete
    Vtilt.capture(
      distinct_id: current_user.id.to_s,
      event: 'purchase_completed',
      properties: { amount: 99.99 },
    )
    render json: { ok: true }
  end
end
ruby

#4. Run captures via Active Job

For low-latency endpoints, push the capture to a background job so analytics never blocks the user-facing response.

# app/jobs/vtilt_capture_job.rb
class VtiltCaptureJob < ApplicationJob
  queue_as :default

  def perform(distinct_id, event, properties = {})
    Vtilt.capture(distinct_id: distinct_id, event: event, properties: properties)
  end
end
ruby
VtiltCaptureJob.perform_later(user.id.to_s, 'subscription_renewed', { plan: user.plan })
ruby

#Next steps

  • Identify & alias — anonymous → known user merge.
  • Event forwarding — fan events out to GA4, Meta CAPI, PostHog.
  • Reverse proxy — block-resistant ingestion.
PreviousPhoenixIntegration guidesNextPythonIntegration guides

On this page

  • 1. Configure credentials
  • 2. Render the SDK in your application layout
  • 3. Server-side capture helper
  • 4. Run captures via Active Job
  • Next steps