mbuzz 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/lib/mbuzz/client/session_request.rb +19 -2
- data/lib/mbuzz/client.rb +5 -2
- data/lib/mbuzz/fbp.rb +20 -0
- data/lib/mbuzz/middleware/session_endpoint.rb +4 -1
- data/lib/mbuzz/middleware/tracking.rb +4 -1
- data/lib/mbuzz/version.rb +1 -1
- data/lib/mbuzz.rb +4 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff302e119aa981ced654677a020929b3b2065055961e253b08e106b52750fed4
|
|
4
|
+
data.tar.gz: ed21ef016dcbac2bb9918a07f03efcce264b9f01046a1ada510e526a107c7ed1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6f9e1ff36c152c2eaa085892b41f7e18e995f7de122413d6d42cc4d44d2199f6e8fa3096ce2e06be4b87a6b2a8daaebcaf80d037e11e85df9298d9b3a33f7e27
|
|
7
|
+
data.tar.gz: 1a18bdf46411b450c247396d595e094404d6b8f7ef487560c8af697c65317f2f6efcf1969a0a86b3a9b349a95f89fd0dce5b546a4d9d5307dd99cf0a3b9d3f85
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.11.0] - 2026-10-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Meta's `_fbp` is forwarded on the session call.** The SDK reads the `_fbp` cookie the customer's
|
|
13
|
+
Meta Pixel already set and sends it as `fbp` on the session payload, on both paths (the session
|
|
14
|
+
endpoint and the tracking middleware). Meta merges a server event with the browser Pixel's event on
|
|
15
|
+
`event_name` + `fbp` when the event IDs differ, so without it every server `Lead` counted as a
|
|
16
|
+
second one. Accepts Meta's `fb.<n>.<ts>.<random>` and the optional appendix its server-side
|
|
17
|
+
Parameter Builder adds (`...AQECAQIB`); anything else is dropped. Never written, never invented.
|
|
18
|
+
The key is omitted, not null, when the cookie is absent or malformed. No install change needed.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **A session call made outside Rack/Rails failed silently.** `SessionRequest` called
|
|
23
|
+
`Time#iso8601` without `require "time"`; Rack and Rails load it, a plain script did not, and the
|
|
24
|
+
`NoMethodError` was rescued to `false`.
|
|
25
|
+
|
|
26
|
+
## [0.10.1] - 2026-09-17
|
|
27
|
+
|
|
28
|
+
### Fixed — the visitor's IP now reaches mbuzz on session create
|
|
29
|
+
|
|
30
|
+
- **`POST /api/v1/sessions` now carries `ip`.** The middleware already extracted the visitor's
|
|
31
|
+
address — it is half of `device_fingerprint = SHA256(ip|user_agent)` — and then dropped it at
|
|
32
|
+
three points on the way out: `Client.session` had no `ip:` keyword, `SessionRequest#payload`
|
|
33
|
+
omitted it, and `Middleware::Tracking`'s own call site omitted it too. Events and conversions have
|
|
34
|
+
always sent one; only sessions did not.
|
|
35
|
+
- **Why it matters.** mbuzz sends Meta's Conversions API `client_ip_address`, which Meta documents
|
|
36
|
+
as **required** for website events, and a session with no address means the events resolved
|
|
37
|
+
through it carry none either. Upgrading improves Event Match Quality for anyone using conversion
|
|
38
|
+
feedback; it changes nothing else.
|
|
39
|
+
- **No API change.** `ip:` is an optional keyword on `Client.session` and both middlewares fill it
|
|
40
|
+
automatically. Existing callers need no edit.
|
|
41
|
+
|
|
42
|
+
Found by the SDK integration harness rather than by unit tests: every layer was correct on its own,
|
|
43
|
+
and only a real request through a real app could tell the visitor's address from the app server's.
|
|
44
|
+
|
|
8
45
|
## [0.10.0] - 2026-09-08
|
|
9
46
|
|
|
10
47
|
### BREAKING — the page snippet is now required
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Time#iso8601 lives here, not in core. Rack and Rails load it; a plain script
|
|
4
|
+
# did not, and the session call then failed silently (rescued to false).
|
|
5
|
+
require "time"
|
|
6
|
+
|
|
3
7
|
module Mbuzz
|
|
4
8
|
class Client
|
|
5
9
|
class SessionRequest
|
|
@@ -12,7 +16,8 @@ module Mbuzz
|
|
|
12
16
|
# Response values
|
|
13
17
|
ACCEPTED_STATUS = "accepted"
|
|
14
18
|
|
|
15
|
-
def initialize(visitor_id:, session_id:, url:, referrer: nil, device_fingerprint: nil,
|
|
19
|
+
def initialize(visitor_id:, session_id:, url:, referrer: nil, device_fingerprint: nil,
|
|
20
|
+
user_agent: nil, started_at: nil, ip: nil, fbp: nil)
|
|
16
21
|
@visitor_id = visitor_id
|
|
17
22
|
@session_id = session_id
|
|
18
23
|
@url = url
|
|
@@ -20,6 +25,8 @@ module Mbuzz
|
|
|
20
25
|
@device_fingerprint = device_fingerprint
|
|
21
26
|
@user_agent = user_agent
|
|
22
27
|
@started_at = started_at
|
|
28
|
+
@ip = ip
|
|
29
|
+
@fbp = fbp
|
|
23
30
|
end
|
|
24
31
|
|
|
25
32
|
def call
|
|
@@ -32,7 +39,8 @@ module Mbuzz
|
|
|
32
39
|
|
|
33
40
|
private
|
|
34
41
|
|
|
35
|
-
attr_reader :visitor_id, :session_id, :url, :referrer, :device_fingerprint, :user_agent,
|
|
42
|
+
attr_reader :visitor_id, :session_id, :url, :referrer, :device_fingerprint, :user_agent,
|
|
43
|
+
:started_at, :ip, :fbp
|
|
36
44
|
|
|
37
45
|
def valid?
|
|
38
46
|
present?(visitor_id) && present?(session_id) && present?(url)
|
|
@@ -42,6 +50,11 @@ module Mbuzz
|
|
|
42
50
|
@response ||= Api.post_with_response(SESSIONS_PATH, { session: payload })
|
|
43
51
|
end
|
|
44
52
|
|
|
53
|
+
# `ip` is the visitor's address, which the middleware already extracted to
|
|
54
|
+
# compute `device_fingerprint` (SHA256(ip|user_agent)). It was computed
|
|
55
|
+
# and then dropped here until 2026-09-17: mbuzz needs it for Meta's
|
|
56
|
+
# `client_ip_address`, which Meta documents as required for website
|
|
57
|
+
# events, and the events/conversions payloads have always carried it.
|
|
45
58
|
def payload
|
|
46
59
|
{
|
|
47
60
|
visitor_id: visitor_id,
|
|
@@ -50,6 +63,10 @@ module Mbuzz
|
|
|
50
63
|
referrer: referrer,
|
|
51
64
|
device_fingerprint: device_fingerprint,
|
|
52
65
|
user_agent: user_agent,
|
|
66
|
+
ip: ip,
|
|
67
|
+
# Meta's browser id, already format-checked by Mbuzz::Fbp. Dropped by
|
|
68
|
+
# .compact when absent: omitted, not null.
|
|
69
|
+
fbp: fbp,
|
|
53
70
|
started_at: started_at || Time.now.utc.iso8601
|
|
54
71
|
}.compact
|
|
55
72
|
end
|
data/lib/mbuzz/client.rb
CHANGED
|
@@ -32,7 +32,8 @@ module Mbuzz
|
|
|
32
32
|
).call
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def self.session(visitor_id:, session_id:, url:, referrer: nil, device_fingerprint: nil,
|
|
35
|
+
def self.session(visitor_id:, session_id:, url:, referrer: nil, device_fingerprint: nil,
|
|
36
|
+
user_agent: nil, started_at: nil, ip: nil, fbp: nil)
|
|
36
37
|
SessionRequest.new(
|
|
37
38
|
visitor_id: visitor_id,
|
|
38
39
|
session_id: session_id,
|
|
@@ -40,7 +41,9 @@ module Mbuzz
|
|
|
40
41
|
referrer: referrer,
|
|
41
42
|
device_fingerprint: device_fingerprint,
|
|
42
43
|
user_agent: user_agent,
|
|
43
|
-
started_at: started_at
|
|
44
|
+
started_at: started_at,
|
|
45
|
+
ip: ip,
|
|
46
|
+
fbp: fbp
|
|
44
47
|
).call
|
|
45
48
|
end
|
|
46
49
|
end
|
data/lib/mbuzz/fbp.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mbuzz
|
|
4
|
+
# Meta's browser id, written client-side by the customer's Meta Pixel. Read
|
|
5
|
+
# only, never set: forwarded on the session call so Meta can merge mbuzz's
|
|
6
|
+
# server event with the Pixel's browser event.
|
|
7
|
+
module Fbp
|
|
8
|
+
# Meta's documented shape, fb.<subdomainIndex>.<creationTime>.<random>, plus
|
|
9
|
+
# the optional appendix Meta's server-side Parameter Builder adds
|
|
10
|
+
# (fb.1.<ts>.<random>.AQECAQIB). Both are valid to Meta. \A…\z, not ^…$:
|
|
11
|
+
# `$` matches before a trailing newline.
|
|
12
|
+
FORMAT = /\Afb\.\d+\.\d+\.\d+(?:\.[A-Za-z0-9_-]+)?\z/
|
|
13
|
+
|
|
14
|
+
# The Pixel's _fbp, or nil when absent or not in Meta's format. mbuzz never
|
|
15
|
+
# invents one and never rewrites what it forwards.
|
|
16
|
+
def self.read(value)
|
|
17
|
+
value if value.is_a?(String) && FORMAT.match?(value)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -67,6 +67,7 @@ module Mbuzz
|
|
|
67
67
|
referrer: payload["referrer"],
|
|
68
68
|
ip: ip,
|
|
69
69
|
user_agent: user_agent,
|
|
70
|
+
fbp: Fbp.read(request.cookies[FBP_COOKIE_NAME]),
|
|
70
71
|
device_fingerprint: Digest::SHA256.hexdigest("#{ip}|#{user_agent}")[0, 32]
|
|
71
72
|
}.freeze
|
|
72
73
|
end
|
|
@@ -93,7 +94,9 @@ module Mbuzz
|
|
|
93
94
|
url: context[:url],
|
|
94
95
|
referrer: context[:referrer],
|
|
95
96
|
device_fingerprint: context[:device_fingerprint],
|
|
96
|
-
user_agent: context[:user_agent]
|
|
97
|
+
user_agent: context[:user_agent],
|
|
98
|
+
ip: context[:ip],
|
|
99
|
+
fbp: context[:fbp]
|
|
97
100
|
)
|
|
98
101
|
rescue StandardError => e
|
|
99
102
|
log_error("Session creation failed: #{e.message}") if Mbuzz.config.debug
|
|
@@ -102,6 +102,7 @@ module Mbuzz
|
|
|
102
102
|
referrer: request.referer,
|
|
103
103
|
ip: ip,
|
|
104
104
|
user_agent: user_agent,
|
|
105
|
+
fbp: Fbp.read(request.cookies[FBP_COOKIE_NAME]),
|
|
105
106
|
device_fingerprint: Digest::SHA256.hexdigest("#{ip}|#{user_agent}")[0, 32]
|
|
106
107
|
}.freeze
|
|
107
108
|
end
|
|
@@ -133,7 +134,9 @@ module Mbuzz
|
|
|
133
134
|
url: context[:url],
|
|
134
135
|
referrer: context[:referrer],
|
|
135
136
|
device_fingerprint: context[:device_fingerprint],
|
|
136
|
-
user_agent: context[:user_agent]
|
|
137
|
+
user_agent: context[:user_agent],
|
|
138
|
+
ip: context[:ip],
|
|
139
|
+
fbp: context[:fbp]
|
|
137
140
|
)
|
|
138
141
|
end
|
|
139
142
|
|
data/lib/mbuzz/version.rb
CHANGED
data/lib/mbuzz.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative "mbuzz/version"
|
|
|
4
4
|
require_relative "mbuzz/configuration"
|
|
5
5
|
require_relative "mbuzz/dropped_call"
|
|
6
6
|
require_relative "mbuzz/visitor/identifier"
|
|
7
|
+
require_relative "mbuzz/fbp"
|
|
7
8
|
require_relative "mbuzz/request_context"
|
|
8
9
|
require_relative "mbuzz/api"
|
|
9
10
|
require_relative "mbuzz/client"
|
|
@@ -29,6 +30,9 @@ module Mbuzz
|
|
|
29
30
|
VISITOR_COOKIE_PATH = "/"
|
|
30
31
|
VISITOR_COOKIE_SAME_SITE = "Lax"
|
|
31
32
|
|
|
33
|
+
# Meta Pixel's browser id. Read only; see Mbuzz::Fbp.
|
|
34
|
+
FBP_COOKIE_NAME = "_fbp"
|
|
35
|
+
|
|
32
36
|
# The one request a cached page always sends to the app. Kept off /api and
|
|
33
37
|
# /assets so host-app routing and cache rules don't shadow it.
|
|
34
38
|
SESSION_ENDPOINT_PATH = "/_mbuzz/session"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mbuzz
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- mbuzz team
|
|
@@ -47,6 +47,7 @@ files:
|
|
|
47
47
|
- lib/mbuzz/controller_helpers.rb
|
|
48
48
|
- lib/mbuzz/current.rb
|
|
49
49
|
- lib/mbuzz/dropped_call.rb
|
|
50
|
+
- lib/mbuzz/fbp.rb
|
|
50
51
|
- lib/mbuzz/middleware/session_endpoint.rb
|
|
51
52
|
- lib/mbuzz/middleware/tracking.rb
|
|
52
53
|
- lib/mbuzz/railtie.rb
|