agency operations7 min readBy Phloz team

Agency client portal: the honest buyer's guide (2026)

What an agency client portal actually does in 2026 — messaging, public task visibility, magic-link auth, shared assets — and what most portal products silently get wrong about agency multi-tenancy.

A client portal is the second-most-common ask from agencies after "where do I store the GA4 password." It's also the second-most-likely feature to ship as a half-built afterthought that nobody opens after week two.

This is the buyer's guide we wish existed when we were evaluating the build-vs-buy decision for Phloz. Honest assessment of what an agency client portal needs to do, what it doesn't, and the multi-tenancy footguns most portal products silently get wrong.

What an agency client portal actually has to do

There are five jobs an agency client portal does. In rough order of how often the client actually uses each:

  1. See the work in progress. Tasks tagged "client-visible," with status (in progress / blocked / done), no internal notes leaking through.
  2. Reply to messages. Either via email round-trip (the agency sends from the portal, the client replies from their inbox, it lands back in the agency's portal) or via a portal-side reply box. Most clients prefer the email round-trip and don't actually log in.
  3. Access shared assets. Brand kit links, the Loom recording of the last call, the latest Google Doc. Read-only links — no upload from the portal side because then you're suddenly a file-sync product.
  4. Self-service contact updates. "I'm leaving, our new marketing lead is Alex." Single form, persists.
  5. Lightweight project visibility — a one-screen "where are we at" view. NOT a Gantt chart. Clients don't want a Gantt chart.

That's it. A client portal that does these five things in 2026 beats 80% of what's out there. Everything beyond this is feature creep.

What clients explicitly DO NOT want

We asked agencies running portals from Basecamp / SuiteDash / ClientPortal / Notion-shared-page / built-in-house. The pattern from the client side was consistent:

  • Not another login. Magic links land in their email; they click through; they see what they need; they close the tab. Username/password is friction.
  • Not a notification firehose. They want one digest per week, max. Not a Slack-style ping per status change.
  • Not "your project" page nobody updates. A portal page that says the same thing for three weeks running is worse than no portal — it actively signals the agency isn't doing anything.
  • Not a kitchen-sink dashboard. The five things above, clean, readable on mobile. Adding a Gantt + a budget tracker + a calendar + invoicing is how portals stop getting opened.

The multi-tenancy footguns

This is where the silent bugs live. Most portal products were built either (a) as a single-tenant product retrofitted into multi-tenant, or (b) by a team that doesn't understand row-level security and reaches for "we check the workspace_id in the controller." Both routes lead to data leaks.

Magic-link tokens identify the portal session, but downstream APIs need to enforce which workspace's data the portal session can see. If the portal calls a generic /api/messages?clientId=X endpoint that does authorization based on the session user (not the magic-link's scoped client), an attacker who guesses a clientId from a different workspace can read messages.

The right fix is a portal-scoped session token whose JWT claim names BOTH the workspace AND the specific client_contact id, and row-level security on the database that enforces messages.workspace_id = jwt.workspace_id regardless of what the API layer does. The DB is the last line of defence.

Many portal products issue one magic-link per contact and reuse it forever. That's effectively a permanent password that's been emailed and forwarded and screenshot'd. Real-world consequence: a contact's old assistant has portal access for two years after they left the company.

The fix is single-use magic links that issue a session cookie on first use, AND scheduled rotation (the cookie expires in 7-30 days; expired ⇒ re-request a fresh magic link).

Footgun 3: "client-visible" task flags applied at render time

A task with visibility = "internal" is fine — until someone marks it client_visible to share a status update, then later adds an internal note in the same task's comment thread. If the comment-visibility check happens at render-time in the React component (and that component runs on the server but reads from a query that returned ALL comments), the internal note leaks.

The fix: filter at the query level — the portal's API only ever returns rows where visibility = 'client_visible'. Render-time filtering is too late, and easy to forget on a new comment field.

Footgun 4: file uploads from the portal side

Once a portal accepts uploads, it inherits all of: virus scanning, file-size limits, storage quotas per workspace, retention policies, and the legal question of "whose data is this when the contract ends." Most portal products that ship upload either ignore these or implement them badly. The pragmatic choice for an agency portal: no portal-side uploads in v1. Clients send files via email (which already has its own attachment limits + virus scanning). Agency uploads agency-side, sharing happens via read-only links.

Footgun 5: portal pricing per contact, not per agency

Some portal products charge per portal-accessing contact. An agency with 30 clients and an average of 3 contacts each = 90 portal seats × $5/mo = $450/mo on portal access alone. That math doesn't work for most agencies. The structural answer is viewer seats are free; the agency pays for paid seats (the agency staff who log in to do work) and clients/contacts are unlimited. We made this an explicit pricing decision in Phloz's tier config for exactly this reason.

What "good" looks like in 2026

A clean agency portal in 2026 is:

  • Magic-link entry, never a separate password. The client clicks the link, lands on their view, doesn't think about auth.
  • One canonical "client-visible" surface — tasks + messages + shared assets — at /portal/[token] or a vanity subdomain.
  • Mobile-clean — 60%+ of portal opens are from a phone. If your portal doesn't render well on iPhone Safari, agencies will get complaints.
  • Branded enough to look professional, not so branded that the agency has to maintain a whole white-label theming system. Agency logo at top, agency name in titles, that's plenty for V1. Full white-label can come later if there's customer demand.
  • Database-level isolation — RLS policies on every tenant table. The API layer is the friendly check; the DB is the security check.
  • Quiet by default — weekly digest is the right default, not real-time pings. Each notification preference per-contact, not global.

Build vs buy: how to decide

Honest take after watching half a dozen agencies make this decision:

  • Buy if you don't have engineering capacity AND the portal is one part of a larger product (CRM + tasks + portal). Half the value of a portal is that it integrates with the rest of the system you're already using to manage clients. A standalone portal that doesn't know about your task system is a worse experience than no portal.
  • Build if you have a strong differentiation idea AND >5 engineering hires AND the portal is core enough to your offering that you'd rather not depend on a third party's roadmap. Build is a 3-6-month commitment if you want it done right (including the RLS work above).
  • Build a thin shim if your existing PM tool (Linear / Asana / Monday) gives you most of what you need but you want a custom subdomain. This is the worst long-term path — you end up reimplementing 60% of the portal anyway as customer-facing tweaks pile up. Skip.

The most common right answer for a sub-50-person agency: buy something integrated with the rest of the CRM stack, configure the five core jobs above, ignore the kitchen-sink features.

How Phloz's portal works

Brief plug — the portal we ship is the one we wished existed:

  • Magic link from /portal/[token] with single-use issue + 7-day session cookie. Rotation built in (re-issued automatically when expiring within 48h).
  • Five surfaces: dashboard summary, messages, public tasks, shared assets, contact-info self-edit. Mobile-clean. Branded with the agency's name + colour.
  • Database-level RLS on every tenant table — messages, tasks, client_contacts, client_assets, all scoped to workspace_id = jwt_workspace_id AND in portal mode further scoped to the specific client_id. The DB enforces isolation even if the API layer has a bug.
  • No portal-side file uploads. Agency uploads on agency side; sharing is via read-only links.
  • Free viewer seats; client contacts unlimited. Per the pricing model.

See the client portal feature page for the product detail, or start a free workspace to test it against your own client. Companion reading: agency client onboarding checklist.