Giter VIP home page Giter VIP logo

customerio-ruby's Introduction

Power automated communication that people like to receive.

Gitpod Ready-to-Code ci

Customer.io Ruby

A ruby client for the Customer.io Track API.

Installation

Add this line to your application's Gemfile:

gem 'customerio'

And then execute:

$ bundle

Or install it yourself:

$ gem install customerio

Usage

Before we get started: API client vs. JavaScript snippet

It's helpful to know that everything below can also be accomplished through the Customer.io JavaScript snippet.

In many cases, using the JavaScript snippet will be easier to integrate with your app, but there are several reasons why using the API client is useful:

  • You're not planning on triggering emails based on how customers interact with your website (e.g. users who haven't visited the site in X days)
  • You're using the javascript snippet, but have a few events you'd like to send from your backend system. They will work well together!
  • You'd rather not have another javascript snippet slowing down your frontend. Our snippet is asynchronous (doesn't affect initial page load) and very small, but we understand.

In the end, the decision on whether or not to use the API client or the JavaScript snippet should be based on what works best for you. You'll be able to integrate fully with Customer.io with either approach.

Setup

Create an instance of the client with your Customer.io credentials.

If you're using Rails, create an initializer config/initializers/customerio.rb:

$customerio = Customerio::Client.new("YOUR SITE ID", "YOUR API SECRET KEY", region: Customerio::Regions::US)

region is optional and takes one of two values—US or EU. If you do not specify your region, we assume that your account is based in the US (US). If your account is based in the EU and you do not provide the correct region (EU), we'll route requests to our EU data centers accordingly, however this may cause data to be logged in the US.

Identify logged in customers

Tracking data of logged in customers is a key part of Customer.io. In order to send triggered emails, we must know the email address of the customer. You can also specify any number of customer attributes which help tailor Customer.io to your business.

Attributes you specify are useful in several ways:

  • As customer variables in your triggered emails. For instance, if you specify the customer's name, you can personalize the triggered email by using it in the subject or body.

  • As a way to filter who should receive a triggered email. For instance, if you pass along the current subscription plan (free / basic / premium) for your customers, you can set up triggers which are only sent to customers who have subscribed to a particular plan (e.g. "premium").

You'll want to identify your customers when they sign up for your app and any time their key information changes. This keeps Customer.io up to date with your customer information.

# Arguments
# attributes (required) - a hash of information about the customer. You can pass any
#                         information that would be useful in your triggers. You 
#                         must at least pass in an id, email, and created_at timestamp.

$customerio.identify(
  :id => 5,
  :email => "[email protected]",
  :created_at => customer.created_at.to_i,
  :first_name => "Bob",
  :plan => "basic"
)

Updating customers: Changing identifiers

You can use the identify operation to update customers. If you need to change the id or email identifiers for a customer, you will need to pass in the cio_id identifier. cio_id is a unique identifier set by Customer.io, used to reference a person, and cannot be changed.

E.g.: if the customer created in the identify operation above was given the cio_id of "f000000d", you could change its ID and email address using:

$customerio.identify(
  :cio_id => "f000000d",
  :id => 1005,
  :email => "[email protected]"
)

This method requires either the id or cio_id for the person. It does not work with email addresses.

You can also use this method to make other updates to the person using the cio_id.

Updating customers: Using email address

If you need to identify a person using their email address, then you can do so by passing in a customer ID to the identify method. This allows you to specify a customer ID that is different than the one used in the id attribute. E.g.:

# Arguments
# customer_id (required) - the customer ID to use for this customer, may be an id, email address, or the cio_id.
#                         This will be used to construct the URL but not sent in the body attributes.
# attributes (required) - a hash of information about the customer. You can pass any
#                         information that would be useful in your triggers. You
#                         must at least pass in an id, email, and created_at timestamp.

$customerio.identify(
  :customer_id => "[email protected]",
  :location => "Australia"
)

Note:

  • If you want to use the cio_id in the customer_id field of identify_customer_id, you will need to prefix it with "cio_". E.g.: "cio_f000000d" for a cio_id of f000000d.
  • The identify method can identify the person using one of customer_id, cio_id or id. The order of precedence is customer_id > cio_id > id.

Deleting customers

Deleting a customer will remove them, and all their information from Customer.io. Note: if you're still sending data to Customer.io via other means (such as the javascript snippet), the customer could be recreated.

# Arguments
# customer_id (required) - a unique identifier for the customer.  This
#                          should be the same id you'd pass into the
#                          `identify` command above.

$customerio.delete(5)

Merge duplicate customer profiles

When you merge two people, you pick a primary person and merge a secondary, duplicate person into it. The primary person remains after the merge and the secondary is deleted. This process is permanent: you cannot recover the secondary person.

The first and third parameters represent the identifier for the primary and secondary people respectively—one of id, email, or cio_id. The second and fourth parameters are the identifier values for the primary and secondary people respectively.

# $customerio.merge_customers("primaryType", "primaryIdentifier", "secondaryType", "secondaryIdentifier")
# primaryType / secondaryType are one of "id", "email", or "cio_id"
# primaryIdentifier / secondaryIdentifier are the identifier value corresponding to the type.

# merge customer "[email protected]" into "[email protected]"
$customerio.merge_customers("email", "[email protected]", "email", "[email protected]")

Tracking a custom event

Now that you're identifying your customers with Customer.io, you can now send events like "purchased" or "watchedIntroVideo". These allow you to more specifically target your users with automated emails, and track conversions when you're sending automated emails to encourage your customers to perform an action.

# Arguments
# customer_id (required) - the id of the customer who you want to associate with the event.
# name (required)        - the name of the event you want to track.
# attributes (optional)  - any related information you'd like to attach to this
#                          event. These attributes can be used in your triggers to control who should
#                          receive the triggered email. You can set any number of data values.

$customerio.track(5, "purchase", :type => "socks", :price => "13.99")

Note: If you want to track events which occurred in the past, you can include a timestamp attribute (in seconds since the epoch), and we'll use that as the date the event occurred.

$customerio.track(5, "purchase", :type => "socks", :price => "13.99", :timestamp => 1365436200)

Tracking anonymous events

You can also send anonymous events, for situations where you don't yet have a customer record yet. An anonymous event requires an anonymous_id representing the unknown person and an event name. When you identify a person, you can set their anonymous_id attribute. If event merging is turned on in your workspace, and the attribute matches the anonymous_id in one or more events that were logged within the last 30 days, we associate those events with the person.

Anonymous events cannot trigger campaigns by themselves. To trigger a campaign, the anonymous event must be associated with a person within 72 hours of the track_anonymous request.

# Arguments
# anonymous_id (required, nullable) - the id representing the unknown person.
# name (required)                   - the name of the event you want to track.
# attributes (optional)             - related information you want to attach to the event.

$customerio.track_anonymous(anonymous_id, "product_view", :type => "socks" )

Use the recipient attribute to specify the email address to send the messages to. See our documentation on how to use anonymous events for more details.

Anonymous invite events

If you previously sent invite events, you can achieve the same functionality by sending an anonymous event with nil for the anonymous identifier. To send anonymous invites, your event must include a recipient attribute.

$customerio.track_anonymous(nil, "invite", :recipient => "[email protected]" )

Adding a mobile device

To send push notifications, you can add ios and android device tokens to a customer:

$customerio.add_device(5, "my_ios_device_id", "ios")
$customerio.add_device(5, "my_android_device_id", "android")

Optionally, last_used can be passed in to specify the last touch of the device. Otherwise, this attribute is set by the API.

$customerio.add_device(5, "my_ios_device_id", "ios", {:last_used=>Time.now.to_i})

Removing a mobile device

Deleting a device token will remove it from the associated customer to stop further push notifications from being sent for that device

$customerio.delete_device(5, "my_device_token")

Suppress a user

Deletes the customer with the provided id if it exists and suppresses all future events and identifies for that customer.

$customerio.suppress(5)

Unsuppress a user

Start tracking events and identifies again for a previously suppressed customer. Note when a user is suppressed thier history is deleted and unsupressing them wil not recover that history.

$customerio.unsuppress(5)

Send Transactional Messages

To use the Customer.io Transactional API, create an instance of the API client using an app key and create a request object of your message type.

Email

Create a new SendEmailRequest object containing:

  • transactional_message_id: the ID of the transactional message you want to send, or the body, from, and subject of a new message.
  • to: the email address of your recipients
  • an identifiers object containing the id of your recipient. If the id does not exist, Customer.io creates it.
  • a message_data object containing properties that you want reference in your message using liquid.
  • You can also send attachments with your message. Use attach to encode attachments.

Use send_email referencing your request to send a transactional message. Learn more about transactional messages and SendEmailRequest properties.

require "customerio"

client = Customerio::APIClient.new("your API key", region: Customerio::Regions::US)

request = Customerio::SendEmailRequest.new(
  to: "[email protected]",
  transactional_message_id: "3",
  message_data: {
    name: "Person",
    items: {
      name: "shoes",
      price: "59.99",
    },
    products: [],
  },
  identifiers: {
    id: "2",
  },
)

file = File.open('<file-path>', 'r')
request.attach("filename", file.read)

begin
  response = client.send_email(request)
  puts response
rescue Customerio::InvalidResponse => e
  puts e.code, e.message
end

Push

Create a new SendPushRequest object containing:

  • transactional_message_id: the ID or trigger name of the transactional message you want to send.
  • an identifiers object containing the id or email of your recipient. If the profile does not exist, Customer.io creates it.

Use send_push referencing your request to send a transactional message. Learn more about transactional messages and SendPushRequest properties.

require "customerio"

client = Customerio::APIClient.new("your API key", region: Customerio::Regions::US)

request = Customerio::SendPushRequest.new(
  transactional_message_id: "3",
  message_data: {
    name: "Person",
    items: {
      name: "shoes",
      price: "59.99",
    },
    products: [],
  },
  identifiers: {
    id: "2",
  },
)

begin
  response = client.send_push(request)
  puts response
rescue Customerio::InvalidResponse => e
  puts e.code, e.message
end

Contributing

  1. Fork it
  2. Clone your fork (git clone [email protected]:MY_USERNAME/customerio-ruby.git && cd customerio-ruby)
  3. Create your feature branch (git checkout -b my-new-feature)
  4. Commit your changes (git commit -am 'Added some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create new Pull Request

customerio-ruby's People

Contributors

alisdair avatar clabland avatar colbymelvin avatar djanhjo avatar gasi avatar glosier avatar hownowstephen avatar jatinn avatar jcmuller avatar joepurdy avatar joshnabbott avatar jrallison avatar karngyan avatar kemper avatar kjleitz avatar loopj avatar lukemelia avatar mcls avatar olleolleolle avatar pavanmachavolu avatar pfeiffer avatar reinaris avatar richdawe-cio avatar sandstrom avatar sdawson avatar stayhero avatar sud0n1m avatar swastik avatar tiutalk avatar y-yagi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

customerio-ruby's Issues

Add a way to list customers

Today I tried to clean up my customer.io list programmatically, but apparently there is no way to list the customers via API (either Ruby or REST).

Could you consider supporting this?

Thanks!

Socket reuse?

I would like to know if it's possible to use the customer io client to send event/track requests using the same socket, either using HTTP/1.1 keep-alive or HTTP/2. A use case would be sending a specific email to all subscribers of an entity. The main API is causing a bit of overhead when you have to send more than one event/request.

Batch-sending could also fix it, but I assume that the server doesn't support it.

Making Beta Request

Is there any support or a plan to make request to the BETA API? We need to fetch account ids from users in a particular segment.

asynchronous support?

From what I understood in the code, all the requests are done in a synchronous way.
Is there some wrapper or suggestion how to wrap these requests to perform async?
So I don't need to hurt my throughput when adding dozens of requests...
Thanks!

Tagged Releases

Tags are missing for gem releases after v1.0.0

The following versions have been released and are untagged:

Screenshot 2021-03-03 at 17 51 25

Please tag your releases, it makes it easier for users of your gem to browse the source of any released version.

Track push notification opens

Feature request

Hello, and thank you for this gem! I was wondering if you had any plans to support the tracking of push notification opened events? Details for the current method of tracking such events can be found in the Technical Integration Guide.

At the moment, my organization uses this gem for just about every interaction with customer.io, with the exception of tracking push notifications. We've ended up rolling our own track method for this specific use case, but I think we'd prefer the ability to track push notifications via this Ruby client.

If this is something you'd consider supporting, I'd be happy to work on a solution myself and submit a PR. Just LMK!

SSL Error when using gem

I can use the REST API fine from Ruby or cURL, but when I use the 0.5.0 gem today, I get this on an identify call:

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

Was working fine yesterday.

Occasional Errno::EBADF via Sidekiq. Thread-safety issues?

We've seen an Errno::EBADF: Bad file descriptor error from this lib twice in the past 3 weeks.

It runs in Sidekiq jobs (meaning it's multi-threaded). My suspicion is that it's a thread-safety issue where if two requests overlap, they might both try to close the same connection/socket causing this error.

I'm not close to expert at threading or networking so this is a complete guess.

Backtrace:

/opt/ruby/lib/ruby/3.2.0/openssl/ssl.rb:387 :in 'close'
/opt/ruby/lib/ruby/3.2.0/openssl/ssl.rb:387 :in 'sysclose'
/opt/ruby/lib/ruby/3.2.0/openssl/buffering.rb:485 in 'close'
/opt/ruby/lib/ruby/3.2.0/net/http.rb:1357 in 'rescue in connect'
/opt/ruby/lib/ruby/3.2.0/net/http.rb:1253 in 'connect'
/opt/ruby/lib/ruby/3.2.0/net/http.rb:1248 in 'do_start'
/opt/ruby/lib/ruby/3.2.0/net/http.rb:1237 :in 'start'
[GEM_ROOT]/gems/customerio-5.0.0/lib/customerio/base_client.rb:62:in 'execute'
[GEM_ROOT]/gems/customerio-5.0.0/lib/customerio/base_client.rb:28:in 'request'

Anonymous events

Hi,

I tried to create and send some "anonymous events" (after checking the gem code, of course) and I found out that they are useless (I hope not), because the event data won't show up in the customer.io interface.

So, should this method be removed from the gem?

Cheers.

id should be url encoded when used in the delete url

Hello.
We use the email address as id for users that want to subscribe to the newsletter but have no user account.
When the user subsequently creates a real account, we delete the existing record based on email address and add a new one with an integer id.

# Remove possible newsletter signup from customer
Customerio::Client.new(id,key).delete(user.email)

We recently have a user that has an accented character in the "local" part of the email address (ex: abcdé[email protected]). The delete call fails with the following error:

An URI::InvalidURIError occurred in signups#create:
 bad URI(is not URI?): /api/v1/customers/abcdé[email protected]
 app/models/user_observer.rb:14:in `after_create'

I'm not sure that this is a valid email address (I probably is according to the RFC), but I think you should probably make the lib more robust and url encode the passed id.

specs are failing

I'm trying to run specs on this project, and most of them fail on a similar error

  26) Customerio::Client#anonymous_track allows sending of a timestamp
      Failure/Error: http.request(req)

      WebMock::NetConnectNotAllowedError:
        Real HTTP connections are disabled. Unregistered request: POST https://track.customer.io/api/v1/events with body 'name=purchase&data[type]=socks&data[price]=27.99&data[timestamp]=1561235678&timestamp=1561235678' with headers {'Authorization'=>'Basic U0lURV9JRDpBUElfS0VZ', 'Content-Type'=>'application/x-www-form-urlencoded'}

        You can stub this request with the following snippet:

        stub_request(:post, "https://track.customer.io/api/v1/events").
          with(:body => {"data"=>{"type"=>"socks", "price"=>"27.99", "timestamp"=>"1561235678"}, "name"=>"purchase", "timestamp"=>"1561235678"},
               :headers => {'Authorization'=>'Basic U0lURV9JRDpBUElfS0VZ', 'Content-Type'=>'application/x-www-form-urlencoded'}).
          to_return(:status => 200, :body => "", :headers => {})

        registered request stubs:

        stub_request(:post, "https://SITE_ID:[email protected]/api/v1/events").
          with(:body => {"data"=>{"type"=>"socks", "price"=>"27.99", "timestamp"=>"1561235678"}, "name"=>"purchase", "timestamp"=>"1561235678"})

        ============================================================
      # /usr/local/bundle/gems/webmock-2.3.2/lib/webmock/http_lib_adapters/net_http.rb:114:in `request'
      # ./lib/customerio/client.rb:119:in `block in request'
      # /usr/local/bundle/gems/webmock-2.3.2/lib/webmock/http_lib_adapters/net_http.rb:123:in `start_without_connect'
      # /usr/local/bundle/gems/webmock-2.3.2/lib/webmock/http_lib_adapters/net_http.rb:150:in `start'
      # ./lib/customerio/client.rb:118:in `request'
      # ./lib/customerio/client.rb:79:in `create_event'
      # ./lib/customerio/client.rb:73:in `create_anonymous_event'
      # ./lib/customerio/client.rb:53:in `anonymous_track'
      # ./spec/client_spec.rb:349:in `block (3 levels) in <top (required)>'

It looks like the client no longer passes the SITE_ID and API_KEY in the URL, but rather adds a basic authentication Authorization header, but the tests weren't updated to reflect this?

Gem enforces ancient version of HTTPparty

Guys,

The pinning of HTTParty introduced in: 9552435

is pretty uncool. HTTParty is a common lib used by lots of other gems, and forcing it to an old version which globally restricts your projects usage of httpparty across all gems.

IMHO, 1.8.7 compatibility (which seems what this restriction was implemented for) is not worth it at all. 1.8.7 was EOL'd in 2012, and stopped receiving security updates in 2013. Those few people stuck on 1.8.7 would be best served with a tagged 1_8_7_stable branch or some such.

https://www.ruby-lang.org/en/news/2011/10/06/plans-for-1-8-7/

How to track page view events?

I see methods like trackPageView in the Python SDK, but not in this Ruby SDK. Based on the suggestion here, I tried sending the page view events like

client.track(15, 'page', path: '/whatever')

but those just appear as "regular" events in the activity log, not actually events of type pageView. How can I use this SDK to send events that will actually come through to the dashboard as page views?

Customerio::Client::InvalidResponse error does not display message

If a Customerio::Client::InvalidResponse error is raised (e.g., in Customerio::Client#verify_response at lib/customerio/client.rb:146 on the master branch, or at lib/customerio/client.rb:95 in v1.0.0), it does not show the error message associated with the exception:

2.3.3 :001 > raise Customerio::Client::InvalidResponse.new("this is the message", "this is the response data")
Customerio::Client::InvalidResponse: Customerio::Client::InvalidResponse
	from (irb):1
	from /Users/keegan/.rvm/gems/ruby-2.3.3@openbay/gems/railties-4.2.7/lib/rails/commands/console.rb:110:in `start'
	from /Users/keegan/.rvm/gems/ruby-2.3.3@openbay/gems/railties-4.2.7/lib/rails/commands/console.rb:9:in `start'
	from /Users/keegan/.rvm/gems/ruby-2.3.3@openbay/gems/railties-4.2.7/lib/rails/commands/commands_tasks.rb:68:in `console'
	[...]

...whereas you would expect the message to be in the output, like this:

2.3.3 :002 > raise Customerio::Client::InvalidResponse.new("this is the message", "this is the response data")
Customerio::Client::InvalidResponse: this is the message
	from (irb):2
	from /Users/keegan/.rvm/gems/ruby-2.3.3@openbay/gems/railties-4.2.7/lib/rails/commands/console.rb:110:in `start'
	from /Users/keegan/.rvm/gems/ruby-2.3.3@openbay/gems/railties-4.2.7/lib/rails/commands/console.rb:9:in `start'
	from /Users/keegan/.rvm/gems/ruby-2.3.3@openbay/gems/railties-4.2.7/lib/rails/commands/commands_tasks.rb:68:in `console'
	[...]

Since it doesn't, there's no way to see the response payload or the HTTP error code, expected here:

# lib/customerio/client.rb

# ...

    def verify_response(response)
      if response.code.to_i >= 200 && response.code.to_i < 300
        response
      else
        raise InvalidResponse.new("Customer.io API returned an invalid response: #{response.code}", response)
      end
    end

# ...

[Feature Request] Add support for deduplicating events with event IDs

From the documentation

From https://customer.io/docs/journeys/events/#deduplicating-events

You can provide an id with your events, to deduplicate events—if there’s a possibility that your integration might send duplicate events. The id must be a ULID. If two events contain the same id, we won’t process the event multiple times.

Deduplicating events helps you accurately represent people’s activity; can prevent people from accidentally entering or leaving campaigns based on the number of times that a person performed an event; and prevents duplicate events from impacting your workspace’s performance.

{
    "name": "my event",
    "id": "01BX5ZZKBKACTAV9WEVGEMMVRY",
    "data": {
        "prop1": "value"
    }
}

Relevant code

def create_customer_event(customer_id, event_name, attributes = {})
create_event(
url: "#{customer_path(customer_id)}/events",
event_name: event_name,
attributes: attributes
)
end

def create_event(url:, event_name:, anonymous_id: nil, event_type: nil, attributes: {})
body = { :name => event_name, :data => attributes }
body[:timestamp] = attributes[:timestamp] if valid_timestamp?(attributes[:timestamp])
body[:anonymous_id] = anonymous_id unless is_empty?(anonymous_id)
body[:type] = event_type unless is_empty?(event_type)
@client.request_and_verify_response(:post, url, body)
end

def track(customer_id, event_name, attributes = {})
raise ParamError.new("customer_id must be a non-empty string") if is_empty?(customer_id)
raise ParamError.new("event_name must be a non-empty string") if is_empty?(event_name)
create_customer_event(customer_id, event_name, attributes)
end

Problem

As you can see, the expected JSON has a top-level id attribute. However, the existing code doesn't allow for this. Apart from a handful exceptions, it nests all attributes into a data object.

This means users of the gem currently don't have a way to provide an id to prevent duplicate events.

Proposed fix

Add an (optional) id parameter to create_event and all methods that reference it. Pass it as a top-level key to the API.

This will be a backwards-compatible change, as current implementations won't currently provide an id directly into the create_event calls. Notably, any id that might be included in the attributes hash continue to work as before.

def track(customer_id, event_name, attributes = {}) needs to be updated too. This is a bit trickier, because it uses positional arguments. I think adding a fourth, optional argument does the trick: def track(customer_id, event_name, attributes = {}, id = nil)

Optionally, the following code can be used to validate the correctness of the id:

def valid_ulid?(ulid)
  !!(ulid =~ /\A[0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz]{26}\z/)
end

content-available: 1 is not attached to a transactional message

I'm working with an Expo mobile project, in which I'm trying to listen to background notifications.
I managed to get it working through the customer.io transactional dashboard, using this custom payload:

{
  "aps": {
    "alert": {
      "title": "Customer.io push from dashboard",
      "body": "with content-available: 1"
    },
    "mutable-content": 1,
    "content-available": 1,
    "sound": "default"
  }
}

When I try with the ruby gem using custom_payload on the request body, I get none of the background listeners to execute, but I get the push notification. I suspect "content-available": 1 is not getting carried over to the transactional message payload

request = Customerio::SendPushRequest.new(
   ....
   custom_payload: {
      ios: {
          aps: {
             "content-available": 1
          },
      },
   },
)

Any pointers would be greatly appreciated!

Updating A Customer Using cio_id Replaces id Attribute

If there is a workspace that uses both id and email as identifiers, then the cio_id must be passed as the id in order to update the email:

{ id: "cio_<customerio id>", email: "[email protected]" }

This works fine, but then passes the id attribute in the request body, which results in the customer's id attribute also being updated to "cio_<customerio id>". It doesn't seem possible to use the "cio_<customerio id>" in the customer url and not overwrite the id attribute for the customer.

It seems like whichever attribute key is used here (in this case :id) to build the customer_path should not be automatically included in the request body.

Add support for batch api

Our use case is to update user properties daily. We batch-load hundreds of users at a time from DB but send one request per user using this library.

It's not a significant pain as we are in the low thousands, but we are growing steadily, which will become a problem. I'm hoping you have a chance to add this before it does, or I'll have to resort to either submitting a PR or making a httparty :-)

Relevant news article: https://www.customer.io/docs/release-notes/2023-01-10-track-v2-api/

Concider seeting a default timeout

Customerio::Client does not set a default_timeout causing HTTParty to try to connect to the API endpoint "forever" if there are networking problems.

My current workaround is something like that:

klass = Customerio::Client.tap {|klass|
  klass.default_options.reverse_merge!(
    timeout: 1.0
  )
}

klass.new(...).identify(...)

execution expired - Net::OpenTimeout

Sometimes I get a timeout error for API calls such as $customerio.identify:
Backtrace:

Message: execution expired
/app/vendor/ruby-2.6.6/lib/ruby/2.6.0/net/http.rb:947 initialize
/app/vendor/ruby-2.6.6/lib/ruby/2.6.0/net/http.rb:947 open
/app/vendor/ruby-2.6.6/lib/ruby/2.6.0/net/http.rb:947 block in connect
/app/vendor/ruby-2.6.6/lib/ruby/2.6.0/timeout.rb:103 timeout
/app/vendor/ruby-2.6.6/lib/ruby/2.6.0/net/http.rb:945 connect
/app/vendor/ruby-2.6.6/lib/ruby/2.6.0/net/http.rb:930 do_start
/app/vendor/ruby-2.6.6/lib/ruby/2.6.0/net/http.rb:919 start
/app/vendor/bundle/ruby/2.6.0/gems/customerio-2.2.1/lib/customerio/client.rb:199 request
/app/vendor/bundle/ruby/2.6.0/gems/customerio-2.2.1/lib/customerio/client.rb:138 create_or_update
/app/vendor/bundle/ruby/2.6.0/gems/customerio-2.2.1/lib/customerio/client.rb:30 identify
  1. Having the function return an error for timeout means that we should wrap up every API call in a begin statement. Is this the intended behavior? I would prefer it not to throw an error in this case.
  2. Can we control the timeout threshold? I would not like it to be more than 3 seconds.

anonymous tracking without anonymous_id

The documentation states that (emphasis mine):

We call it an Invite Event when you send an event >>>without an anonymous_id and include a data.recipient key<<. You can use these events to trigger invite emails to people you haven't yet identified.

There's also a table below with the list of possible / required params

image

However, the track_anonymous method requires an anonymous_id, and the code snippet on the documentation page covers only the case with an anonymous_id:

$customerio = Customerio::Client.new("YOUR SITE ID", "YOUR API SECRET KEY", region: Customerio::Regions::US)

$customerio.track_anonymous(anonymous_id, "help_enquiry", :subject => 'anon-events')

Any suggestions on how to continue using anonymous events to be able to trigger campaigns for email addresses, rather than users on customer.io?

Only working with json: true on Initialize

I'm not sure if this is happening to anyone else but I was having an issue getting the gem to post information to Customer.io without sending it as json. Here is the code that was running.

CUSTOMERIO = Customerio::Client.new(
  Rails.configuration.customerio[:site_id], 
  Rails.configuration.customerio[:api_secret])

Upon a user signing up I had this for sending code:

if @team.org.org_type.id == 1
  setup = @team.is_setup?
  CUSTOMERIO.identify(
    id: @team.id,
    email: @user.email,
    created_at: @user.created_at,
    first_name: @user.first_name,
    last_name: @user.last_name,
    team_cars: @team.list_cars,
    plan: @plan.name,
    is_setup: setup
  )
end

However, when it was run on staging it would not work unless we added some type of breakpoint after the .identify() call such as a binding.pry or a puts to the console.

I am not quite sure what was going on but the fix I found was just giving the initialize json: true option.

Has anyone else run into this issue? If so, is there another way to fix this?

Add support to identify customers by email instead of always requiring an ID

The docs and API allow you to identify people with only an email if the customer is not a fully onboarded user yet (i.e. a lead). However, if you try to identify a user through the library and don't supply a id it errors out, specifically at this line of code.

Right now I am getting around this issue by not using the client and instead using the API directly. It would be nice if I didn't have to do that. Happy to make the code change but it looks like other contributors PRs aren't being merged?

Not possible to set headers on a SendEmailRequest

The SendEmailRequest class accepts a headers: option, but the value provided will always be overwritten with an empty hash. See line 10 below:

def initialize(opts)
@message = opts.delete_if { |field| invalid_field?(field) }
@message[:attachments] = {}
@message[:headers] = {}
end

Is this a typo for ||=?

For now I'll work around it by modifying the returned object directly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.