Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tracker feature to automatically track outbound links #389

Merged
merged 5 commits into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.

### Added
- Ability to add event metadata plausible/analytics#381
- Add tracker module to automatically track outbound links plausible/analytics#389
- Display weekday on the visitor graph plausible/analytics#175

### Changed
Expand Down
55 changes: 0 additions & 55 deletions lib/plausible_web/controllers/tracker_controller.ex

This file was deleted.

1 change: 1 addition & 0 deletions lib/plausible_web/endpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ defmodule PlausibleWeb.Endpoint do
extra: "SameSite=Lax"

plug CORSPlug
plug PlausibleWeb.Tracker
plug PlausibleWeb.Router
end
45 changes: 45 additions & 0 deletions lib/plausible_web/plugs/tracker.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
defmodule PlausibleWeb.Tracker do
import Plug.Conn
@templates [
"plausible.js",
"plausible.hash.js",
"plausible.hash.outbound-links.js",
"plausible.outbound-links.js",
"p.js"
]
@aliases %{
"plausible.js" => ["analytics.js"],
"plausible.hash.outbound-links.js" => ["plausible.outbound-links.hash.js"]
}

#  1 hour
@max_age 3600

def init(_) do
templates = Enum.reduce(@templates, %{}, fn template_filename, rendered_templates ->
rendered = EEx.eval_file("priv/tracker/js/" <> template_filename, base_url: PlausibleWeb.Endpoint.url())
aliases = Map.get(@aliases, template_filename, [])
[template_filename | aliases]
|> Enum.map(fn filename -> {"/js/" <> filename, rendered} end)
|> Enum.into(%{})
|> Map.merge(rendered_templates)
end)

[templates: templates]
end

def call(conn, templates: templates) do
case templates[conn.request_path] do
found when is_binary(found) -> send_js(conn, found)
nil -> conn
end
end

defp send_js(conn, file) do
conn
|> put_resp_header("cache-control", "max-age=#{@max_age},public")
|> put_resp_header("content-type", "application/javascript")
|> send_resp(200, file)
|> halt()
end
end
5 changes: 0 additions & 5 deletions lib/plausible_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ defmodule PlausibleWeb.Router do
forward "/sent-emails", Bamboo.SentEmailViewerPlug
end

get "/js/plausible.js", PlausibleWeb.TrackerController, :plausible
get "/js/plausible.hash.js", PlausibleWeb.TrackerController, :plausible_hash
get "/js/analytics.js", PlausibleWeb.TrackerController, :plausible
get "/js/p.js", PlausibleWeb.TrackerController, :p

scope "/api/stats", PlausibleWeb.Api do
pipe_through :stats_api

Expand Down
1 change: 1 addition & 0 deletions priv/tracker/js/plausible.hash.outbound-links.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions priv/tracker/js/plausible.outbound-links.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions tracker/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ function compilefile(input, output, templateVars = {}) {

compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.js'))
compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.hash.js'), {hashMode: true})
compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.outbound-links.js'), {outboundLinks: true})
compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.hash.outbound-links.js'), {hash: true, outboundLinks: true})
compilefile(relPath('src/p.js'), relPath('../priv/tracker/js/p.js'))
fs.copyFileSync(relPath('../priv/tracker/js/plausible.js'), relPath('../priv/tracker/js/analytics.js'))
35 changes: 35 additions & 0 deletions tracker/src/plausible.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,38 @@
}
}

{{#if outboundLinks}}
function trackOutboundLink(event) {
var link = event.target;
while (link && (typeof link.tagName == 'undefined' || link.tagName.toLowerCase() != 'a' || !link.href)) {
link = link.parentNode;
}

if (link && link.href) {
plausible('Outbound Link: Click', {meta: {url: link.href}})
}

// Delay navigation so that Plausible is notified of the click
if(!link.target || link.target.match(/^_(self|parent|top)$/i)) {
setTimeout(function() { location.href = link.href; }, 150);
event.preventDefault();
}
}

function registerOutboundLinkEvents() {
window.addEventListener('load', function() {
var links = document.getElementsByTagName('a')

for (var i = 0; i < links.length; ++i) {
var link = links[i]
if (link.host !== location.host) {
link.addEventListener('click', trackOutboundLink);
}
}
});
}
{{/if}}

try {
var his = window.history
if (his.pushState) {
Expand All @@ -65,6 +97,9 @@
{{#if hashMode}}
window.addEventListener('hashchange', page)
{{/if}}
{{#if outboundLinks}}
registerOutboundLinkEvents()
{{/if}}


var queue = (window.plausible && window.plausible.q) || []
Expand Down