Anyone can put a web app in an iframe and call it a GoHighLevel app. The difference between that and something an agency can actually run their business on is a short list of unglamorous things.
1. SSO, so nobody has a second password
If your team has to create an account in a tool that already lives inside a CRM they are logged into, you have added friction to every single user, forever. A marketplace app should decrypt the GoHighLevel SSO payload and log the user straight in inside the iframe. Zero extra logins is not a nicety; it is the difference between a tool your team uses and a tool your team avoids.
Keep a standalone login too — for use outside the CRM — but make it the exception.
2. OAuth chooselocation, and then find the rest yourself
Authorize against the agency, let the user pick the locations, and then stop asking. New sub-accounts should be discovered by a background worker, not added by hand. An agency that adds four clients a month should not have to remember to add four clients a month to your app as well.
And back it with a token-refresh worker. An OAuth integration that silently dies over a weekend is worse than no integration.
3. The webhooks — all of them, including the one you do not want
Contact create, update, delete, custom field, tag. Message inbound and outbound. Appointment create, update, delete. Location create and update.
And app.uninstall.
The uninstall webhook is the one that tells you whether an app was built by people who intend to be trusted. Handle it: stop the workers for that account, revoke the tokens, delete the cached CRM data. An app that keeps syncing after it has been removed is not an integration; it is a problem.
Verify the signatures. All of them.
4. Respect the rate limits, structurally
Do not call the CRM API on every page load. Serve reads from a cache, refresh in the background when the cache is stale, and push the delta to the browser over an event stream. Queue writes locally and drain them with a worker rather than firing them at the API the instant a user hits save.
This is not politeness. An app that hammers the API is slow on a good day and broken on a bad one, and it degrades the CRM for every other app your customer has installed.
5. Be embeddable, and prove it
The marketplace lets you render your app inside the CRM. Use it. Power CRM’s fax module renders as an embedded app inside GoHighLevel — the client’s staff send and receive fax in the CRM they already have open. That pattern is available to any module, and it is what makes an app feel native rather than adjacent.
None of this shows up in a demo. All of it shows up in month four.