Only count new visitors in referrer report

This commit is contained in:
Uku Taht 2020-01-16 15:40:06 +02:00
parent 9df398b663
commit 423db302f7
7 changed files with 122 additions and 20 deletions

View File

@ -17,10 +17,15 @@ class ReferrerDrilldownModal extends React.Component {
}
componentDidMount() {
const include = this.showBounceRate() ? 'bounce_rate' : null
if (this.state.query.filters.goal) {
api.get(`/api/stats/${this.props.site.domain}/goal/referrers/${this.props.match.params.referrer}`, this.state.query, {limit: 100})
.then((res) => this.setState({loading: false, referrers: res.referrers, totalVisitors: res.total_visitors}))
} else {
const include = this.showBounceRate() ? 'bounce_rate' : null
api.get(`/api/stats/${this.props.site.domain}/referrers/${this.props.match.params.referrer}`, this.state.query, {limit: 100, include: include})
.then((res) => this.setState({loading: false, referrers: res.referrers, totalVisitors: res.total_visitors}))
api.get(`/api/stats/${this.props.site.domain}/referrers/${this.props.match.params.referrer}`, this.state.query, {limit: 100, include: include})
.then((res) => this.setState({loading: false, referrers: res.referrers, totalVisitors: res.total_visitors}))
}
}
showBounceRate() {

View File

@ -16,10 +16,15 @@ class ReferrersModal extends React.Component {
}
componentDidMount() {
const include = this.showBounceRate() ? 'bounce_rate' : null
if (this.state.query.filters.goal) {
api.get(`/api/stats/${this.props.site.domain}/goal/referrers`, this.state.query, {limit: 100})
.then((res) => this.setState({loading: false, referrers: res}))
} else {
const include = this.showBounceRate() ? 'bounce_rate' : null
api.get(`/api/stats/${this.props.site.domain}/referrers`, this.state.query, {limit: 100, include: include})
.then((res) => this.setState({loading: false, referrers: res}))
api.get(`/api/stats/${this.props.site.domain}/referrers`, this.state.query, {limit: 100, include: include})
.then((res) => this.setState({loading: false, referrers: res}))
}
}
showBounceRate() {

View File

@ -24,8 +24,13 @@ export default class Referrers extends React.Component {
}
fetchReferrers() {
api.get(`/api/stats/${this.props.site.domain}/referrers`, this.props.query)
.then((res) => this.setState({loading: false, referrers: res}))
if (this.props.query.filters.goal) {
api.get(`/api/stats/${this.props.site.domain}/goal/referrers`, this.props.query)
.then((res) => this.setState({loading: false, referrers: res}))
} else {
api.get(`/api/stats/${this.props.site.domain}/referrers`, this.props.query)
.then((res) => this.setState({loading: false, referrers: res}))
}
}
renderReferrer(referrer) {

View File

@ -163,14 +163,25 @@ defmodule Plausible.Stats do
))
end
def top_referrers(site, query, limit \\ 5, include \\ []) do
referrers = Repo.all(from e in base_query(site, query),
def top_referrers_for_goal(site, query, limit \\ 5) do
Repo.all(from e in base_query(site, query),
select: %{name: e.referrer_source, count: count(e.user_id, :distinct)},
group_by: e.referrer_source,
where: not is_nil(e.referrer_source),
order_by: [desc: 2],
limit: ^limit
)
end
def top_referrers(site, query, limit \\ 5, include \\ []) do
referrers = Repo.all(from e in base_query(site, query),
select: %{name: e.referrer_source, count: count(e)},
group_by: e.referrer_source,
where: not is_nil(e.referrer_source),
where: e.new_visitor,
order_by: [desc: 2],
limit: ^limit
)
if "bounce_rate" in include do
bounce_rates = bounce_rates_by_referrer_source(site, query, Enum.map(referrers, fn ref -> ref[:name] end))
@ -220,6 +231,15 @@ defmodule Plausible.Stats do
end
def visitors_from_referrer(site, query, referrer) do
Repo.one(
from e in base_query(site, query),
select: count(e),
where: e.new_visitor,
where: e.referrer_source == ^referrer
)
end
def conversions_from_referrer(site, query, referrer) do
Repo.one(
from e in base_query(site, query),
select: count(e.user_id, :distinct),
@ -230,9 +250,10 @@ defmodule Plausible.Stats do
def referrer_drilldown(site, query, referrer, include \\ []) do
referring_urls = Repo.all(
from e in base_query(site, query),
select: %{name: e.referrer, count: count(e.user_id, :distinct)},
select: %{name: e.referrer, count: count(e)},
group_by: e.referrer,
where: e.referrer_source == ^referrer,
where: e.new_visitor,
order_by: [desc: 2],
limit: 100
)
@ -263,6 +284,17 @@ defmodule Plausible.Stats do
end
end
def referrer_drilldown_for_goal(site, query, referrer) do
Repo.all(
from e in base_query(site, query),
select: %{name: e.referrer, count: count(e.user_id, :distinct)},
group_by: e.referrer,
where: e.referrer_source == ^referrer,
order_by: [desc: 2],
limit: 100
)
end
defp bounce_rates_by_referring_url(site, query, referring_urls) do
{first_datetime, last_datetime} = date_range_utc_boundaries(query.date_range, site.timezone)

View File

@ -73,6 +73,12 @@ defmodule PlausibleWeb.Api.StatsController do
json(conn, Stats.top_referrers(site, query, params["limit"] || 5, include))
end
def referrers_for_goal(conn, params) do
site = conn.assigns[:site]
query = Stats.Query.from(site.timezone, params)
json(conn, Stats.top_referrers_for_goal(site, query, params["limit"] || 5))
end
@google_api Application.fetch_env!(:plausible, :google_api)
@ -109,6 +115,15 @@ defmodule PlausibleWeb.Api.StatsController do
json(conn, %{referrers: referrers, total_visitors: total_visitors})
end
def referrer_drilldown_for_goal(conn, %{"referrer" => referrer} = params) do
site = conn.assigns[:site]
query = Stats.Query.from(site.timezone, params)
referrers = Stats.referrer_drilldown_for_goal(site, query, referrer)
total_visitors = Stats.conversions_from_referrer(site, query, referrer)
json(conn, %{referrers: referrers, total_visitors: total_visitors})
end
def pages(conn, params) do
site = conn.assigns[:site]
query = Stats.Query.from(site.timezone, params)

View File

@ -37,7 +37,9 @@ defmodule PlausibleWeb.Router do
get "/:domain/current-visitors", StatsController, :current_visitors
get "/:domain/main-graph", StatsController, :main_graph
get "/:domain/referrers", StatsController, :referrers
get "/:domain/goal/referrers", StatsController, :referrers_for_goal
get "/:domain/referrers/:referrer", StatsController, :referrer_drilldown
get "/:domain/goal/referrers/:referrer", StatsController, :referrer_drilldown_for_goal
get "/:domain/pages", StatsController, :pages
get "/:domain/countries", StatsController, :countries
get "/:domain/browsers", StatsController, :browsers

View File

@ -5,11 +5,11 @@ defmodule PlausibleWeb.Api.StatsController.ReferrersTest do
describe "GET /api/stats/:domain/referrers" do
setup [:create_user, :log_in, :create_site]
test "returns top referrer sources by unique visitors", %{conn: conn, site: site} do
pageview1 = insert(:pageview, hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 01:00:00])
insert(:pageview, hostname: site.domain, referrer_source: "Google", user_id: pageview1.user_id, timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, hostname: site.domain, referrer_source: "Bing", timestamp: ~N[2019-01-01 02:00:00])
test "returns top referrer sources by new visitors", %{conn: conn, site: site} do
insert(:pageview, hostname: site.domain, referrer_source: "Google", new_visitor: true, timestamp: ~N[2019-01-01 01:00:00])
insert(:pageview, hostname: site.domain, referrer_source: "Google", new_visitor: false, timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, hostname: site.domain, referrer_source: "Google", new_visitor: true, timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, hostname: site.domain, referrer_source: "Bing", new_visitor: true, timestamp: ~N[2019-01-01 02:00:00])
conn = get(conn, "/api/stats/#{site.domain}/referrers?period=day&date=2019-01-01")
@ -34,27 +34,31 @@ defmodule PlausibleWeb.Api.StatsController.ReferrersTest do
%{"name" => "Bing", "count" => 1, "bounce_rate" => nil},
]
end
end
test "filters referrers for a custom goal", %{conn: conn, site: site} do
describe "GET /api/stats/:domain/goal/referrers" do
setup [:create_user, :log_in, :create_site]
test "returns top referrers for a custom goal", %{conn: conn, site: site} do
insert(:event, name: "Signup", hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 01:00:00])
insert(:event, name: "Signup", hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 02:00:00])
filters = Jason.encode!(%{goal: "Signup"})
conn = get(conn, "/api/stats/#{site.domain}/referrers?period=day&date=2019-01-01&filters=#{filters}")
conn = get(conn, "/api/stats/#{site.domain}/goal/referrers?period=day&date=2019-01-01&filters=#{filters}")
assert json_response(conn, 200) == [
%{"name" => "Google", "count" => 2},
]
end
test "filters referrers for a pageview goal", %{conn: conn, site: site} do
test "returns top referrers for a pageview goal", %{conn: conn, site: site} do
insert(:pageview, pathname: "/register", hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 01:00:00])
insert(:pageview, pathname: "/register", hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 01:00:00])
insert(:pageview, pathname: "/irrelevant", hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 02:00:00])
filters = Jason.encode!(%{goal: "Visit /register"})
conn = get(conn, "/api/stats/#{site.domain}/referrers?period=day&date=2019-01-01&filters=#{filters}")
conn = get(conn, "/api/stats/#{site.domain}/goal/referrers?period=day&date=2019-01-01&filters=#{filters}")
assert json_response(conn, 200) == [
%{"name" => "Google", "count" => 2},
@ -150,4 +154,38 @@ defmodule PlausibleWeb.Api.StatsController.ReferrersTest do
assert %{"name" => "t.co/nonexistent-link", "count" => 1, "tweets" => nil} = tweet2
end
end
describe "GET /api/stats/:domain/goal/referrers/:referrer" do
setup [:create_user, :log_in, :create_site]
test "returns top referring urls for a custom goal", %{conn: conn, site: site} do
insert(:event, name: "Signup", hostname: site.domain, referrer_source: "Twitter", referrer: "a", timestamp: ~N[2019-01-01 01:00:00])
insert(:event, name: "Signup", hostname: site.domain, referrer_source: "Twitter", referrer: "a", timestamp: ~N[2019-01-01 02:00:00])
insert(:event, name: "Signup", hostname: site.domain, referrer_source: "Twitter", referrer: "b", timestamp: ~N[2019-01-01 02:00:00])
filters = Jason.encode!(%{goal: "Signup"})
conn = get(conn, "/api/stats/#{site.domain}/goal/referrers/Twitter?period=day&date=2019-01-01&filters=#{filters}")
assert json_response(conn, 200) == %{
"total_visitors" => 3,
"referrers" => [
%{"name" => "a", "count" => 2},
%{"name" => "b", "count" => 1}
]
}
end
test "returns top referring urls for a pageview goal", %{conn: conn, site: site} do
insert(:pageview, pathname: "/register", hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 01:00:00])
insert(:pageview, pathname: "/register", hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 01:00:00])
insert(:pageview, pathname: "/irrelevant", hostname: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 02:00:00])
filters = Jason.encode!(%{goal: "Visit /register"})
conn = get(conn, "/api/stats/#{site.domain}/goal/referrers?period=day&date=2019-01-01&filters=#{filters}")
assert json_response(conn, 200) == [
%{"name" => "Google", "count" => 2},
]
end
end
end