Ruby on Rails Integration Guide
This guide shows you how to add Heyo to your Ruby on Rails application. Compatible with Rails 7, Turbo, and Hotwire.
Installation
Add to Application Layout
Add the Heyo script to app/views/layouts/application.html.erb:
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || "My App" %></title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
<%# Add Heyo before closing head tag %>
<script src="https://heyo.so/embed/script" defer data-project-id="<%= Rails.application.credentials.heyo[:project_id] %>"></script>
</head>
<body>
<%= yield %>
</body>
</html>
Add to config/credentials.yml.enc (edit with rails credentials:edit):
heyo:
project_id: YOUR_PROJECT_ID
Or use environment variables in config/initializers/heyo.rb:
Rails.application.config.heyo_project_id = ENV['HEYO_PROJECT_ID']
Then in your layout:
<script src="https://heyo.so/embed/script" defer data-project-id="<%= Rails.application.config.heyo_project_id %>"></script>
Pass User Data
Method 1: User Check in ERB
<script src="https://heyo.so/embed/script" defer data-project-id="<%= Rails.application.config.heyo_project_id %>"></script>
<% if user_signed_in? %>
<script>
window.addEventListener('load', function() {
if (window.HEYO) {
window.HEYO.init({
projectId: '<%= Rails.application.config.heyo_project_id %>',
user: {
name: '<%= j current_user.name %>',
email: '<%= j current_user.email %>',
id: <%= current_user.id %>
}
});
}
});
</script>
<% end %>
Note: Use j helper (alias for escape_javascript) to safely escape JavaScript strings.
Method 2: JSON Helper
For more complex user data:
<% if user_signed_in? %>
<script>
window.addEventListener('load', function() {
if (window.HEYO) {
window.HEYO.init({
projectId: '<%= Rails.application.config.heyo_project_id %>',
user: <%= raw({
name: current_user.name,
email: current_user.email,
id: current_user.id,
created_at: current_user.created_at.iso8601
}.to_json) %>
});
}
});
</script>
<% end %>
Advanced Usage
Create a Helper Method
Add to app/helpers/application_helper.rb:
module ApplicationHelper
def heyo_widget
project_id = Rails.application.config.heyo_project_id
return unless project_id.present?
content_tag(:script, nil,
src: 'https://heyo.so/embed/script',
defer: true,
'data-project-id': project_id
)
end
def heyo_user_data
return unless user_signed_in?
user_data = {
name: current_user.name,
email: current_user.email,
id: current_user.id
}
javascript_tag do
<<~JS
window.addEventListener('load', function() {
if (window.HEYO) {
window.HEYO.init({
projectId: '#{Rails.application.config.heyo_project_id}',
user: #{user_data.to_json}
});
}
});
JS
end
end
end
Usage in layouts:
<head>
<%= heyo_widget %>
</head>
<body>
<%= yield %>
<%= heyo_user_data %>
</body>
Rails 7 + Turbo Compatibility
Heyo works with Turbo out of the box. The widget persists across Turbo Drive navigations.
If you need to reinitialize on Turbo navigation:
<script>
document.addEventListener('turbo:load', function() {
if (window.HEYO) {
window.HEYO.show();
}
});
</script>
Stimulus Controller Integration
Create app/javascript/controllers/heyo_controller.js:
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
// Controller connected
}
open(event) {
event.preventDefault()
window.HEYO?.show()
}
close(event) {
event.preventDefault()
window.HEYO?.hide()
}
toggle(event) {
event.preventDefault()
window.HEYO?.toggle()
}
}
Usage in views:
<button data-controller="heyo" data-action="click->heyo#open">
Need Help?
</button>
ViewComponent Integration
Create app/components/heyo/widget_component.rb:
# frozen_string_literal: true
module Heyo
class WidgetComponent < ViewComponent::Base
def initialize(user: nil)
@user = user
end
def project_id
Rails.application.config.heyo_project_id
end
def user_data
return nil unless @user
{
name: @user.name,
email: @user.email,
id: @user.id
}
end
end
end
Create app/components/heyo/widget_component.html.erb:
<script src="https://heyo.so/embed/script" defer data-project-id="<%= project_id %>"></script>
<% if user_data %>
<script>
window.addEventListener('load', function() {
if (window.HEYO) {
window.HEYO.init({
projectId: '<%= project_id %>',
user: <%= raw user_data.to_json %>
});
}
});
</script>
<% end %>
Usage:
<%= render Heyo::WidgetComponent.new(user: current_user) %>
Multi-Tenant Applications
For multi-tenant Rails apps:
<%
project_id = current_tenant.heyo_project_id || Rails.application.config.heyo_project_id
%>
<script src="https://heyo.so/embed/script" defer data-project-id="<%= project_id %>"></script>
Content Security Policy
If using CSP, add to config/initializers/content_security_policy.rb:
Rails.application.config.content_security_policy do |policy|
policy.script_src :self, :https, 'https://heyo.so'
policy.connect_src :self, :https, 'wss://heyo.so', 'https://heyo.so'
end
Route-Based Control
Show chat only on specific routes:
<% unless request.path.start_with?('/checkout') %>
<%= heyo_widget %>
<% end %>
Or using route helpers:
<% unless current_page?(checkout_path) %>
<%= heyo_widget %>
<% end %>
Best Practices
- Store Project ID in credentials or environment variables
- Use
jhelper to escape JavaScript strings - Use
to_jsonfor complex data structures - Create helpers or components for reusability
- Check user authentication before passing data
- Test with Turbo Drive navigation
Troubleshooting
Widget not appearing
- Verify HEYO_PROJECT_ID is set
- Check credentials are loaded properly
- Look for JavaScript errors in console
User data not showing
- Use
jhelper for string escaping - Ensure
user_signed_in?returns true - Check JSON encoding is valid
Turbo navigation issues
- Widget should persist by default
- Add turbo:load listener if needed
- Check that script isn't being removed
CSP blocking script
- Add heyo.so to script-src
- Add WebSocket connection to connect-src