{
  "slug": "custom-portals",
  "url": "https://apps.sectorgrowth.com/integrations/custom-portals/",
  "name": "Custom portals",
  "vendor": "Sector Growth",
  "aliases": [
    "Customer portal",
    "Member portal",
    "Partner portal",
    "Client portal",
    "HubSpot portal build"
  ],
  "website": "https://sectorgrowth.com/services/custom-portals",
  "category": {
    "slug": "sales-and-marketing-platforms",
    "name": "Sales and marketing platforms",
    "url": "https://apps.sectorgrowth.com/categories/sales-and-marketing-platforms/"
  },
  "summary": "A portal shows members, partners or clients their own slice of the CRM, with HubSpot as the only system of record and caching as the rate limit defence.",
  "answer": "No, and that is the point. There is no app to install, because a portal is software we build on HubSpot's own API, with HubSpot staying the system of record so your team keeps working in the CRM they already know. It suits member, partner and client portals where records, stages and documents are the content, and a first build runs 70 to 150 hours.",
  "nativeApp": {
    "status": "none",
    "verifiedAt": "2026-09-22"
  },
  "api": {
    "style": "rest",
    "auth": "api-key",
    "webhooks": "yes",
    "changedSince": "yes",
    "sandbox": "yes",
    "rateLimit": "190 requests per 10 seconds for a private app on Professional or Enterprise, with the daily total shared across every app in the account",
    "docsUrl": "https://developers.hubspot.com/docs/guides/api/crm/objects/custom-objects"
  },
  "objects": [
    {
      "source": "Portal sign-in",
      "hubspot": "contact",
      "direction": "two_way",
      "key": "Email address, gated by an access property on the contact",
      "notes": "Turning access off in the CRM locks the account on the next request."
    },
    {
      "source": "Submitted request or referral",
      "hubspot": "deal",
      "direction": "to_hubspot",
      "key": "A portal reference code stored on the deal",
      "notes": "A native deal, so the team works it in the pipeline as usual."
    },
    {
      "source": "Stage tracker",
      "hubspot": "deal",
      "direction": "to_source",
      "key": "Deal stage history, read back by record identifier",
      "notes": "A stage moved in the CRM appears in the portal on the next read."
    },
    {
      "source": "Resource or catalogue item",
      "hubspot": "custom",
      "direction": "to_source",
      "key": "Custom object record, published by the team",
      "notes": "One cached list serves every viewer, which is the rate limit defence."
    },
    {
      "source": "Notification",
      "hubspot": "custom",
      "direction": "to_source",
      "key": "Custom object record, with read state kept in our own database"
    },
    {
      "source": "Invoice or dues record",
      "hubspot": "deal",
      "direction": "to_source",
      "key": "Deal in a billing pipeline, with a payment link out",
      "notes": "No card details touch the portal, which keeps the scope small."
    },
    {
      "source": "Portal activity",
      "hubspot": "engagement",
      "direction": "to_hubspot",
      "key": "Custom behavioural event, keyed to the contact",
      "notes": "Sign-in, record view and submit, so the CRM sees portal behaviour."
    }
  ],
  "approaches": [
    {
      "kind": "custom",
      "fit": "recommended",
      "why": "A server-side portal on HubSpot's API keeps one system of record, keeps the token off the browser, and lets the team publish content and move stages from the CRM without learning a second tool."
    },
    {
      "kind": "native",
      "fit": "possible",
      "why": "HubSpot's own membership and private content features are enough when the requirement is gated pages rather than records, stages, uploads and a per-person view of a pipeline."
    },
    {
      "kind": "ipaas",
      "fit": "avoid",
      "why": "A no-code portal builder usually copies your CRM into its own database, which gives you a second system of record to reconcile and a vendor between your team and your data."
    }
  ],
  "effort": {
    "discoveryHours": [
      10,
      20
    ],
    "buildHours": [
      70,
      150
    ],
    "buildBand": "70 to 150 hours",
    "typicalElapsed": "4 to 8 weeks"
  },
  "pattern": "portal",
  "faqs": [
    {
      "q": "Do we need a HubSpot app to run a customer portal?",
      "a": "No. A portal is not a marketplace listing, it is software that talks to your own portal through HubSpot's API with a private app credential and a defined set of scopes. Nothing is installed in the App Marketplace, and no other customer's account is involved, which is why the security conversation is shorter than people expect."
    },
    {
      "q": "Where does the HubSpot token live in a portal build?",
      "a": "Server side only, in the platform's secret store, and it never reaches the browser. The browser holds a session cookie and nothing else. Every read and write goes through our own functions, which check who is asking before they ask HubSpot, so a user cannot request a record that is not theirs by editing a URL."
    },
    {
      "q": "How does a HubSpot-backed portal stay inside the API rate limits?",
      "a": "Caching is built in from the start rather than tuned in later. Limits are counted per app, so every signed-in user shares one budget. Lists that are the same for everyone are cached once and served to all, per-person reads are cached for around a minute and invalidated on write, and the CRM search endpoint, capped at five requests a second per account, is kept off the hot path."
    },
    {
      "q": "Can portal users see only their own records?",
      "a": "Yes, and it is enforced on the server rather than in the interface. The signed-in contact is resolved from the session, every record read is checked against that contact's own associations, and anything else returns nothing. Hiding a record in the interface is only a convenience, and the ownership check is what controls access."
    },
    {
      "q": "How does the team publish content to the portal?",
      "a": "By creating records in HubSpot. Resources, events and notifications are custom object records, so publishing an item or sending a notice is something the team does in the CRM rather than in a separate admin tool. That is the whole design goal: no second system to keep in step, and no developer in the publishing loop."
    },
    {
      "q": "What does a portal record in HubSpot when somebody signs in?",
      "a": "Custom behavioural events, sent to the events endpoint with the contact identified, covering sign-in, failed sign-in, record views, submissions and downloads. Each occurrence can carry up to 50 properties, and an account can define up to 500 event types. The result is portal behaviour sitting on the contact timeline next to emails and calls."
    },
    {
      "q": "Can a HubSpot-backed portal take payments?",
      "a": "It can show an invoice and link out to a payment provider, which is what we usually recommend, because no card details then pass through the portal and the compliance scope stays small. Taking payment in the page is possible and is a different project, with its own review and its own provider decision."
    },
    {
      "q": "How long does a HubSpot-backed portal take to build?",
      "a": "A first portal covering sign-in, a submission flow, a tracker and a library runs 10 to 20 hours of discovery and 70 to 150 hours of build. The second portal on the same engine is much faster: our own partner portal was forked from an existing member portal and reached a live deployment in five days."
    }
  ],
  "sections": [
    {
      "depth": 2,
      "text": "Why teams connect a custom portal to HubSpot",
      "anchor": "#why-teams-connect-a-custom-portal-to-hubspot",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#why-teams-connect-a-custom-portal-to-hubspot"
    },
    {
      "depth": 2,
      "text": "What syncs",
      "anchor": "#what-syncs",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#what-syncs"
    },
    {
      "depth": 2,
      "text": "Architecture",
      "anchor": "#architecture",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#architecture"
    },
    {
      "depth": 2,
      "text": "Three ways to connect",
      "anchor": "#three-ways-to-connect",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#three-ways-to-connect"
    },
    {
      "depth": 2,
      "text": "What breaks and how we prevent it",
      "anchor": "#what-breaks-and-how-we-prevent-it",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#what-breaks-and-how-we-prevent-it"
    },
    {
      "depth": 3,
      "text": "190 requests every 10 seconds",
      "anchor": "#190-requests-every-10-seconds",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#190-requests-every-10-seconds"
    },
    {
      "depth": 3,
      "text": "Searching on every page load",
      "anchor": "#searching-on-every-page-load",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#searching-on-every-page-load"
    },
    {
      "depth": 3,
      "text": "Stale caches after a submission",
      "anchor": "#stale-caches-after-a-submission",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#stale-caches-after-a-submission"
    },
    {
      "depth": 3,
      "text": "Access revoked after sign-in",
      "anchor": "#access-revoked-after-sign-in",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#access-revoked-after-sign-in"
    },
    {
      "depth": 2,
      "text": "Our approach",
      "anchor": "#our-approach",
      "url": "https://apps.sectorgrowth.com/integrations/custom-portals/#our-approach"
    }
  ],
  "caseStudies": [
    "https://apps.sectorgrowth.com/case-studies/custom-portals-backed-by-hubspot/"
  ],
  "guides": [
    "https://apps.sectorgrowth.com/guides/choose-a-hubspot-integration-approach/"
  ],
  "builtBySectorGrowth": true,
  "status": "published",
  "verifiedAt": "2026-09-22",
  "updatedAt": "2026-09-25",
  "authors": [
    {
      "name": "Prash",
      "role": "Lead of Technical Integrations and AI Solutions"
    }
  ],
  "sources": [
    {
      "title": "Legacy private apps",
      "url": "https://developers.hubspot.com/docs/guides/apps/private-apps/overview"
    },
    {
      "title": "Authentication overview",
      "url": "https://developers.hubspot.com/docs/apps/developer-platform/build-apps/authentication/overview"
    },
    {
      "title": "API usage guidelines and limits",
      "url": "https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines"
    },
    {
      "title": "Custom object records API guide",
      "url": "https://developers.hubspot.com/docs/guides/api/crm/objects/custom-objects"
    },
    {
      "title": "CRM Search API",
      "url": "https://developers.hubspot.com/docs/api-reference/latest/crm/search-the-crm"
    },
    {
      "title": "Send custom event occurrences",
      "url": "https://developers.hubspot.com/docs/guides/api/analytics-and-events/custom-events/custom-event-completions"
    },
    {
      "title": "Create a sandbox and deploy changes to production",
      "url": "https://knowledge.hubspot.com/account-management/deploy-sandbox-changes-to-production"
    }
  ]
}