diff --git a/lib/plausible/goals/goals.ex b/lib/plausible/goals/goals.ex
index 1c1ab51e2..e145df17f 100644
--- a/lib/plausible/goals/goals.ex
+++ b/lib/plausible/goals/goals.ex
@@ -248,6 +248,12 @@ defmodule Plausible.Goals do
:ok
end
+ @spec create_404(Plausible.Site.t()) :: :ok
+ def create_404(%Plausible.Site{} = site) do
+ create(site, %{"event_name" => "404"}, upsert?: true)
+ :ok
+ end
+
@spec delete_outbound_links(Plausible.Site.t()) :: :ok
def delete_outbound_links(%Plausible.Site{} = site) do
q =
@@ -270,6 +276,17 @@ defmodule Plausible.Goals do
:ok
end
+ @spec delete_404(Plausible.Site.t()) :: :ok
+ def delete_404(%Plausible.Site{} = site) do
+ q =
+ from g in Goal,
+ where: g.site_id == ^site.id,
+ where: g.event_name == "404"
+
+ Repo.delete_all(q)
+ :ok
+ end
+
defp insert_goal(site, params, upsert?) do
params = Map.delete(params, "site_id")
diff --git a/lib/plausible_web/live/installation.ex b/lib/plausible_web/live/installation.ex
index 8c7729007..7c6d6c839 100644
--- a/lib/plausible_web/live/installation.ex
+++ b/lib/plausible_web/live/installation.ex
@@ -14,7 +14,8 @@ defmodule PlausibleWeb.Live.Installation do
"file-downloads",
"hash",
"pageview-props",
- "revenue"
+ "revenue",
+ "404"
]
@installation_types [
@@ -226,10 +227,28 @@ defmodule PlausibleWeb.Live.Installation do
"""
end
+ defp render_snippet("manual", domain, %{"404" => true} = script_config) do
+ script_config = Map.put(script_config, "404", false)
+
+ """
+ #{render_snippet("manual", domain, script_config)}
+ #{render_snippet_404("manual")}
+ """
+ end
+
defp render_snippet("manual", domain, script_config) do
~s||
end
+ defp render_snippet("GTM", domain, %{"404" => true} = script_config) do
+ script_config = Map.put(script_config, "404", false)
+
+ """
+ #{render_snippet("GTM", domain, script_config)}
+ #{render_snippet_404("GTM")}
+ """
+ end
+
defp render_snippet("GTM", domain, script_config) do
"""
"
+ end
+
+ def render_snippet_404("GTM") do
+ render_snippet_404("manual")
+ end
+
defp script_extension_control(assigns) do
~H"""
@@ -338,6 +365,13 @@ defmodule PlausibleWeb.Live.Installation do
tooltip="Assign monetary values to purchases and track revenue attribution. Additional action required."
learn_more="https://plausible.io/docs/ecommerce-revenue-tracking"
/>
+ <.script_extension_control
+ config={@script_config}
+ variant="404"
+ label="404 errors"
+ tooltip="Automatically track 404 error pages. Additional action required."
+ learn_more="https://plausible.io/docs/error-pages-tracking-404"
+ />
"""
end
@@ -412,6 +446,16 @@ defmodule PlausibleWeb.Live.Installation do
update_script_config(socket, %{key => false})
end
+ defp update_script_config(socket, "404" = key, true) do
+ Plausible.Goals.create_404(socket.assigns.site)
+ update_script_config(socket, %{key => true})
+ end
+
+ defp update_script_config(socket, "404" = key, false) do
+ Plausible.Goals.delete_404(socket.assigns.site)
+ update_script_config(socket, %{key => false})
+ end
+
defp update_script_config(socket, key, value) do
update_script_config(socket, %{key => value})
end
diff --git a/test/plausible_web/live/installation_test.exs b/test/plausible_web/live/installation_test.exs
index 0fa0a57e4..2123a247d 100644
--- a/test/plausible_web/live/installation_test.exs
+++ b/test/plausible_web/live/installation_test.exs
@@ -183,7 +183,31 @@ defmodule PlausibleWeb.Live.InstallationTest do
end
end
- test "turning on file-downloads and outbound-links creates special goals", %{
+ test "allows manual snippet customization with 404 links", %{conn: conn, site: site} do
+ {lv, _html} = get_lv(conn, site, "?installation_type=manual")
+
+ lv
+ |> element(~s|form#snippet-form|)
+ |> render_change(%{
+ "404" => "on"
+ })
+
+ html = lv |> render()
+
+ assert text_of_element(html, "textarea#snippet") =~
+ "function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>"
+
+ lv
+ |> element(~s|form#snippet-form|)
+ |> render_change(%{})
+
+ html = lv |> render()
+
+ refute text_of_element(html, "textarea#snippet") =~
+ "function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>"
+ end
+
+ test "turning on file-downloads, outbound-links and 404 creates special goals", %{
conn: conn,
site: site
} do
@@ -195,14 +219,16 @@ defmodule PlausibleWeb.Live.InstallationTest do
|> element(~s|form#snippet-form|)
|> render_change(%{
"file-downloads" => "on",
- "outbound-links" => "on"
+ "outbound-links" => "on",
+ "404" => "on"
})
lv |> render()
- assert [clicks, downloads] = Plausible.Goals.for_site(site)
+ assert [clicks, downloads, error_404] = Plausible.Goals.for_site(site)
assert clicks.event_name == "Outbound Link: Click"
assert downloads.event_name == "File Download"
+ assert error_404.event_name == "404"
end
test "turning off file-downloads and outbound-links deletes special goals", %{