Skip to main content

TypeScript vs Go

Both SDKs speak the same contract and the same state model — snapshot + patches in, typed intents out. They differ in language conventions and a few behaviours worth knowing when you build with one or port between them.

Which should I use? Pick by where your code runs, not by preference — they cover different surfaces:

  • TypeScript for anything in a browser — a softphone, CTI, or messaging UI with real WebRTC audio, or the embeddable widget. It's the only SDK that runs in the browser.
  • Go for back-end and terminal apps — services, dashboards, bots, and CLIs that drive calls or react to state server-side. Audio is optional (the default media leg is silent).

You can also run both: a Go service orchestrating calls while a TypeScript front end renders the same AgentView — they're the same model on the wire.

Neither language? You can still integrate over REST/OpenAPI for the unary operations — fetch state, send SMS, pull history/contacts — by generating a client from the downloadable spec. The live state stream rides gRPC(-web) only, so REST gives you the request/response surface, not the push updates (for those you need an SDK).

AspectTypeScript (@babelforce/babelconnect-sdk)Go (babelconnect-sdk-go)
ConnectBabelconnectClient.connect({ serverUrl, token }) — returns synchronously and queues intents until the stream is livebcclient.Dial(ctx, Options{ Addr, Token })blocks until the session is open
Server addressserverUrl — the HTTPS originAddr — the gRPC host:port
TransportgRPC-web: Subscribe (state) + unary Send (intents)native gRPC: the bidirectional Session
Intent methodsreturn void; send failures arrive on onErrorreturn an error (the send result)
autoAnswer defaulttruefalse (the zero value — opt in)
register capabilitiesdefaults to ["webrtc"]variadic — pass "webrtc"
Read state nowbc.view · bc.activeCall()cli.View() · cli.ActiveCall()
Stop a renderersubscribe() returns an unsubscribe fnSubscribe returns nothing — Close() the client
DisconnectonError with disconnectednot signaled — detect from a failing send / stalled updates
NotificationsonNotification callbacknot surfaced
Media legMedia = answer + close; default BrowserWebrtcMedia (real mic/speaker audio)Media = Answer + Stats + Close; default is cgo-free synthetic (silent)
Enum membersunprefixed (CallLifecycle.RINGING)prefixed (CallLifecycle_CALL_LIFECYCLE_RINGING)
passwordGrant client_idoptional clientId overridefixed at "manager"
OAuth / PKCE helpers (authentication)pkceChallenge · buildAuthorizeUrl · authorizationCodeGrant · revokeToken · DEFAULT_CLIENT_IDGeneratePKCE · PkceAuthorizeURL · AuthorizationCodeGrant · DefaultClientIDno revokeToken helper (TS + Dart only); revoke via a direct POST /oauth/revoke
Cleanupawait bc.close() — async (Promise<void>)cli.Close() — returns error, usually defer'd
Concurrencysingle-threaded (the event loop)goroutine-safe — sends are serialised; the Subscribe callback runs on the receive loop

:::caution The register default differs — Go has none TypeScript's register() auto-sends ["webrtc"] when you call it with no arguments. Go's Register() is variadic with no default, so calling Register() with no arguments sends no capability and leaves the agent not WebRTC-reachable — calls won't ring at the client. Pass Register("webrtc") explicitly when porting TypeScript that relied on the bare register(). :::

Everything else — AgentView, the patch types, the intents, presence, wrap-up, conferencing, SMS — is the same on both, so the concepts and the intents reference apply to either. Start at the TypeScript or Go getting-started for the language specifics.

See also

  • Errors & reconnects — the Disconnect and intent-method return rows above in depth: how each SDK signals a dropped stream and where send failures surface.
  • Authentication — the passwordGrant client_id difference, the PKCE helpers on both SDKs, token handling, and the security checklist.