diff --git a/lib/plausible/billing/plans.ex b/lib/plausible/billing/plans.ex
index a508425461a61fc215f1955cd3bd83bc51ff930c..2fbcbbcbd143748fd65ea434caed486a644e089d 100644
--- a/lib/plausible/billing/plans.ex
+++ b/lib/plausible/billing/plans.ex
@@ -27,31 +27,30 @@ defmodule Plausible.Billing.Plans do
   ]
 
   def plans_for(user) do
-    case Application.get_env(:plausible, :environment) do
-      "dev" ->
-        Enum.map(@sandbox_plans, fn plan ->
-          Map.put(plan, :volume, number_format(plan[:limit]))
-        end)
-
-      _ ->
-        real_plans_for(user)
-    end
-  end
-
-  def real_plans_for(user) do
     user = Repo.preload(user, :subscription)
+    sandbox_plans = plans_sandbox()
     v1_plans = plans_v1()
-
-    v1_plan_ids =
-      v1_plans
-      |> Enum.map(fn plan -> [plan[:monthly_product_id], plan[:yearly_product_id]] end)
-      |> List.flatten()
+    v2_plans = plans_v2()
+    v3_plans = plans_v3()
 
     raw_plans =
-      if user.subscription && user.subscription.paddle_plan_id in v1_plan_ids do
-        v1_plans
-      else
-        plans_v2()
+      cond do
+        contains?(v1_plans, user.subscription) ->
+          v1_plans
+
+        contains?(v2_plans, user.subscription) ->
+          v2_plans
+
+        contains?(v3_plans, user.subscription) ->
+          v3_plans
+
+        contains?(sandbox_plans, user.subscription) ->
+          sandbox_plans
+
+        true ->
+          case Application.get_env(:plausible, :environment) do
+            _ -> v3_plans
+          end
       end
 
     Enum.map(raw_plans, fn plan -> Map.put(plan, :volume, number_format(plan[:limit])) end)
@@ -106,15 +105,21 @@ defmodule Plausible.Billing.Plans do
     Enum.find(plans_for(user), fn plan -> usage < plan[:limit] end)
   end
 
+  defp contains?(_plans, nil), do: false
+
+  defp contains?(plans, subscription) do
+    Enum.any?(plans, fn plan ->
+      plan[:monthly_product_id] == subscription.paddle_plan_id ||
+        plan[:yearly_product_id] == subscription.paddle_plan_id
+    end)
+  end
+
   defp number_format(num) do
     PlausibleWeb.StatsView.large_number_format(num)
   end
 
   defp all_plans() do
-    case Application.get_env(:plausible, :environment) do
-      "dev" -> @sandbox_plans
-      _ -> plans_v1() ++ @unlisted_plans_v1 ++ plans_v2() ++ @unlisted_plans_v2
-    end
+    plans_v1() ++ @unlisted_plans_v1 ++ plans_v2() ++ @unlisted_plans_v2 ++ plans_sandbox()
   end
 
   defp plans_v1() do
@@ -126,4 +131,16 @@ defmodule Plausible.Billing.Plans do
     File.read!(Application.app_dir(:plausible) <> "/priv/plans_v2.json")
     |> Jason.decode!(keys: :atoms)
   end
+
+  defp plans_v3() do
+    File.read!(Application.app_dir(:plausible) <> "/priv/plans_v3.json")
+    |> Jason.decode!(keys: :atoms)
+  end
+
+  defp plans_sandbox() do
+    case Application.get_env(:plausible, :environment) do
+      "dev" -> @sandbox_plans
+      _ -> []
+    end
+  end
 end
diff --git a/lib/plausible_web/templates/billing/_paddle_script.html.eex b/lib/plausible_web/templates/billing/_paddle_script.html.eex
index da12a8d489c437588cd5faf45a54f24f74b4d0ec..0f430fb8f58cc30ed206c9615aaab7346a140851 100644
--- a/lib/plausible_web/templates/billing/_paddle_script.html.eex
+++ b/lib/plausible_web/templates/billing/_paddle_script.html.eex
@@ -4,4 +4,4 @@
     Paddle.Environment.set('sandbox');
   <% end %>
   Paddle.Setup({vendor: <%= Application.get_env(:plausible, :paddle) |> Keyword.fetch!(:vendor_id) %> });
-</script>
\ No newline at end of file
+</script>
diff --git a/lib/plausible_web/templates/billing/upgrade.html.eex b/lib/plausible_web/templates/billing/upgrade.html.eex
index ac24ff7306f4853c3b739bf8cba5a2486265d729..e4f3b3248444fa8e612c184b2597b1b8e9407882 100644
--- a/lib/plausible_web/templates/billing/upgrade.html.eex
+++ b/lib/plausible_web/templates/billing/upgrade.html.eex
@@ -34,7 +34,7 @@
           productIds.push(plan.monthly_product_id)
           productIds.push(plan.yearly_product_id)
         })
-        
+
         var checkoutDomain = '<%= Plausible.Billing.PaddleApi.checkout_domain() %>'
         fetchJsonp(checkoutDomain + '/api/2.0/prices?product_ids=' + productIds.join(','))
           .then((res) => res.json())
diff --git a/priv/plans_v3.json b/priv/plans_v3.json
new file mode 100644
index 0000000000000000000000000000000000000000..dc3668e7be73fb63c73b3503915ee5139db26de8
--- /dev/null
+++ b/priv/plans_v3.json
@@ -0,0 +1,59 @@
+[
+  {
+    "limit":10000,
+    "monthly_cost":"$9",
+    "monthly_product_id":"749342",
+    "yearly_cost":"$90",
+    "yearly_product_id":"749343"
+  },
+  {
+    "limit":100000,
+    "monthly_cost":"$19",
+    "monthly_product_id":"749344",
+    "yearly_cost":"$190",
+    "yearly_product_id":"749345"
+  },
+  {
+    "limit":200000,
+    "monthly_cost":"$29",
+    "monthly_product_id":"749346",
+    "yearly_cost":"$290",
+    "yearly_product_id":"749347"
+  },
+  {
+    "limit":500000,
+    "monthly_cost":"$49",
+    "monthly_product_id":"749348",
+    "yearly_cost":"$490",
+    "yearly_product_id":"749349"
+  },
+  {
+    "limit":1000000,
+    "monthly_cost":"$69",
+    "monthly_product_id":"749350",
+    "yearly_cost":"$690",
+    "yearly_product_id":"749352"
+  },
+
+  {
+    "limit":2000000,
+    "monthly_cost":"$89",
+    "monthly_product_id":"749353",
+    "yearly_cost":"$890",
+    "yearly_product_id":"749355"
+  },
+  {
+    "limit":5000000,
+    "monthly_cost":"$129",
+    "monthly_product_id":"749356",
+    "yearly_cost":"$1290",
+    "yearly_product_id":"749357"
+  },
+  {
+    "limit":10000000,
+    "monthly_cost":"$169",
+    "monthly_product_id":"749358",
+    "yearly_cost":"$1690",
+    "yearly_product_id":"749359"
+  }
+]