PHOENIX SEO AUDIT · ELIXIR · LIVEVIEW · AI VISIBILITY
Free Phoenix (Elixir) SEO Audit
Phoenix renders complete HTML server-side before LiveView takes over — no JavaScript rendering gap. But sitemap generation, robots.txt, and per-route metadata all require deliberate implementation. DeepSEOAnalysis audits Phoenix apps and surfaces what's missing, with HEEx assign patterns, Sitemapper config, and Plug.Static paths for each fix.
WHAT WE CHECK
6 Phoenix-specific SEO checks
Beyond the 80+ general checks, the engine applies Phoenix-aware analysis — covering HEEx template assign patterns, Ecto slug fields, Sitemapper hex config, and Plug.Static priv/static/ serving paths.
HEEx template metadata coverage
Phoenix 1.7+ uses HEEx templates with the `<.live_title>` and function components for page metadata. The `app.html.heex` root layout renders `<.live_title prefix="My App | ">` using the `@page_title` assign, and individual controllers or LiveViews set `assign(socket, :page_title, post.title)` or `conn |> assign(:page_title, post.title)` per route. Meta descriptions, canonical URLs, and OG tags require explicit assigns in the layout and per-route assignment. Common gaps: the layout has a static site-name title with no dynamic assign reference; `<meta name="description">` is absent from `root.html.heex`; OG tags are hardcoded to the homepage image and title; LiveView modules `mount/3` functions don't update `:page_title` on navigation. The audit checks every crawled page for a unique, populated title tag and meta description.
Route slug structure
Phoenix routes are defined in `router.ex` with path parameters: `get "/posts/:id", PostController, :show` produces numeric-ID URLs (`/posts/42`); `get "/posts/:slug", PostController, :show` produces clean slug URLs (`/posts/my-post-title`). The slug value must be stored in your Ecto schema — typically a `slug` string field populated via a `Slug.slugify/1` call in a changeset (`ecto_autoslug_field` or `slugify` hex packages). Phoenix LiveView navigation also uses router path params — ensure `live "/posts/:slug", PostLive, :show` uses slug params. Common gaps: numeric `id` used for content-heavy routes, no slug field on the Ecto schema, and API endpoints accessible without `Plug.Router` disallow patterns. The audit flags non-keyword URL patterns and candidates for robots.txt blocking.
Sitemap configuration
Phoenix has no built-in sitemap generator. The standard approach is the `Sitemapper` hex package — configure `Sitemapper.Sitemap` with your Ecto Repo and URL-generating functions in `config.exs`, run generation via a scheduled Oban job or GenServer, and output to `priv/static/sitemap.xml` for automatic static serving. Alternatively, a Phoenix controller endpoint can stream XML dynamically from an Ecto query. Common gaps after implementing: the Ecto query includes unpublished or soft-deleted records; `lastmod` is the generation timestamp rather than the record's `updated_at` field; the sitemap URL is not referenced in `priv/static/robots.txt` as a `Sitemap:` directive; the dynamic sitemap endpoint is not cached and hits the database on every crawler request. The audit checks sitemap presence, coverage, `lastmod` source, and the Sitemap directive.
robots.txt and AI crawler access
Phoenix serves static files from `priv/static/` via `Plug.Static` configured in `endpoint.ex` (`plug Plug.Static, at: "/", from: :your_app, gzip: true`). A `priv/static/robots.txt` file is served correctly at `/robots.txt`. Unlike Flask, there is no common path confusion — the `at: "/"` mount point means static files are served at the URL root. Common gaps: no `robots.txt` exists in `priv/static/` (Phoenix creates none by default); Phoenix admin routes (`/admin`, `/dev/dashboard`, the Phoenix LiveDashboard at `/dev`) are not disallowed; API endpoints (typically `/api/`) lack Disallow rules; AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Applebot) are accidentally blocked by a broad `Disallow: /` wildcard or missing User-agent sections. The audit checks the file path, all major AI crawler user-agents, and common Phoenix admin route patterns.
Server-rendered LiveView advantages
Phoenix LiveView's default rendering model is highly SEO-friendly: the initial page load sends a complete server-rendered HTML response via HTTP before establishing the WebSocket connection for real-time updates. Googlebot receives the full page content, metadata, and structured data on the first request — no JavaScript rendering step, no two-wave crawl queue. Subsequent LiveView interactions (nav, filter, update) happen over the WebSocket and do not affect initial crawl quality. The audit verifies that crawled pages deliver complete HTML in the initial response and flags LiveView patterns where significant content is deferred to the WebSocket stream rather than included in the initial `mount/3` render (uncommon but possible with `connected?/1` guards). Phoenix REST API endpoints returning JSON are flagged for robots.txt Disallow recommendations.
AI visibility for Phoenix apps
Phoenix's `Plug.Static` makes `llms.txt` straightforward: place `priv/static/llms.txt` and it's served at `/llms.txt` automatically via the existing static file configuration. FAQPage JSON-LD can be rendered in HEEx templates as a `<script type="application/ld+json">` tag — pass the structured data as an assign from the controller or LiveView mount, then render with `Jason.encode!(@faq_schema)` in a raw HTML tag (`{:safe, ...}` in HEEx). Article JSON-LD belongs in the blog post layout template. The `jason` library is already included in most Phoenix apps for JSON encoding. The audit checks all five AI visibility signals — llms.txt presence, AI crawler access, FAQPage/HowTo schema, question-heading ratio (≥20%), and content chunkability (avg section ≤400w) — with Phoenix-specific `Plug.Static` config and HEEx component patterns for each fix.
HOW IT WORKS
Audit your Phoenix app in 60 seconds
- Enter your Phoenix app URL. Works with any Phoenix deployment: Fly.io, Gigalixir, Render, Heroku, Railway, bare-metal with nginx, or custom OTP releases. No source code, HEEx templates, or IEx shell access needed — the audit crawls the live site.
- We crawl and analyse. The engine crawls up to 50 pages (free) or 1,000 pages (paid), checks HEEx metadata assign coverage across all crawled routes, validates FAQPage and Article JSON-LD, tests `priv/static/robots.txt` at the correct URL, measures CrUX Core Web Vitals, and evaluates all five AI visibility signals.
- You get a prioritised report. Phoenix-aware issues first — missing assigns in `root.html.heex`, numeric `:id` routing, Sitemapper configuration gaps, missing LiveDashboard Disallow rules, blocked AI crawlers — then general SEO, each with the specific HEEx tag, controller assign pattern, or `config.exs` snippet to fix it.
FAQ
Questions about the Phoenix SEO audit
Does DeepSEOAnalysis detect Phoenix/Elixir-specific SEO issues?
Yes. The engine detects Phoenix signatures — server-rendered HEEx template output, Phoenix router URL patterns, and the priv/static/ directory conventions — and surfaces framework-specific guidance alongside the 80+ general checks.
Is Phoenix good for SEO?
Phoenix is excellent for SEO. It renders HTML server-side via HEEx templates by default, and LiveView sends complete HTML on the initial page load before switching to real-time WebSocket updates for subsequent interactions. Googlebot receives fully-rendered content, metadata, and structured data on the first request with no JavaScript rendering step. Phoenix's main SEO challenges are the same as other minimal frameworks: no built-in sitemap generator, no default robots.txt, and metadata management that requires intentional per-route implementation via assigns.
How do I generate a sitemap in a Phoenix app?
Use the `Sitemapper` hex package — add `{:sitemapper, "~> 0.8"}` to `mix.exs`, configure it with your Repo and list of URL-generating functions in `config.exs`, and run `Sitemapper.generate/2` on a schedule via a GenServer or Oban job. The generated XML file can be placed in `priv/static/sitemap.xml` (served automatically at `/sitemap.xml`) or streamed from a Phoenix controller endpoint. Add a `Sitemap:` directive in `priv/static/robots.txt`. The audit checks sitemap presence, coverage, and the directive.
Is the Phoenix SEO audit free?
Yes. The complete audit is free with no signup and no email gate. Paid plans add saved history, scheduled monitoring, larger crawls (up to 1,000 pages), and agency workflows.