bensheldon / spectator_sport

Record and replay browser sessions in a self-hosted Rails Engine.
https://spectator-sport-demo-1ca285490d99.herokuapp.com/
MIT License
161 stars 3 forks source link

Thoughts on Adding Request Data to the Session #25

Open nathancolgate opened 1 month ago

nathancolgate commented 1 month ago

We've used HotJar on other projects and they have a few nice touches that would be easy to add.

screenshot

Here's something we've done in our application:

class AddRequestDataToSpectatorSportSessions < ActiveRecord::Migration[8.0]
  def change
    add_column :spectator_sport_sessions, :user_agent, :string
    add_column :spectator_sport_sessions, :referrer, :string
    add_column :spectator_sport_sessions, :remote_ip, :string
    add_column :spectator_sport_sessions, :ip_data, :jsonb, default: {}
  end
end

And then in the events_controller.rb:

session = SpectatorSport::Session.create_with(remote_ip: request.remote_ip, user_agent: request.user_agent, referrer: request.referrer).find_or_create_by(secure_id: session_secure_id)

And the session.rb model:

module SpectatorSport
  class Session < ApplicationRecord
    after_commit :fetch_ip_data, on: [:create]

    def fetch_ip_data
      url = "https://api.ip2location.io/?key=#{Rails.application.credentials.dig(:ip_2_location, :api_key)}&ip=#{remote_ip}&format=json"
      uri = URI(url)
      response = Net::HTTP.get(uri)
      update!({
        ip_data: JSON.parse(response)
      })
    end

    def location
      "#{ip_data.dig("city_name")}, #{ip_data.dig("region_name")}"
    end
  end
end

And oh how the sales guys love this:

screenshot
nathancolgate commented 4 weeks ago

Small update: I put the referrer in the session, and added a landing path to get a little more info:

class ApplicationController < ActionController::Base
  before_action :store_referrer_and_path, unless: :active_admin_request?

  private

  def store_referrer_and_path
    # if it's the first page load of the session
    # Capture the referrer
    session["referrer"] ||= request.referrer
    # And the path that they landed on
    session["landing_path"] ||= request.path
  end
end
bensheldon commented 3 weeks ago

Thanks for proposing this! I like it!!

Only thing here that's a nonstarter is making an API request. The gem needs to be entirely self-contained (for availability and privacy). MaxMind GeoLite databases have a license that I think would allow embedding. Though the size is less great. Here's some of the options: https://dev.maxmind.com/geoip/docs/databases/city-and-country/#database-sizes

Probably the simplest path forward would be to omit the location for now, and we could add the other details. Would you be open to making a PR for that?

abdullahdevrel commented 3 weeks ago

Hi, I work for IPinfo. We have a free IP to Country database if you are interested in trying it out.

In terms of embedding, you might want to check MaxMind's EULA and commercial distribution license. In our case, however, we have a CC-BY-SA 4.0 license that allows you to package the IP to Country database and distribute it even for commercial usage. But if you prefer, you can use an embedded access token that downloads the database directly onto the user's machine. That will take care of the size issue altogether.

Let me know if you have any questions or queries about us. Cheers!

nathancolgate commented 3 weeks ago

@bensheldon You bet.

And I totally agree on the call to make it self contained. I can easily see the position being something like:

We capture the raw information provided by Rails (IP, Referrer, Landing Page, User Agent). For availability and privacy, we leave the interpretation of this data up to you. For instance: you might elect to run the IP address through a database or API to get location data.