Interview & Outbound Sales Agents on Bland's Web SDK
What it does
A second implementation of the real-time voice agent suite, rebuilt on Bland's Web Agent SDK to compare platform architectures against the earlier Vapi build. Two agents run in the browser: a staged screening interviewer that probes vague answers and scores against a five-competency rubric across five roles, and an outbound SDR that opens for permission, runs discovery, handles objections and asks for the meeting. The port surfaced real architectural differences — Bland web agents are persistent server-side objects created through POST /v1/agents rather than configs passed inline at call time, the transport is a raw WebSocket carrying PCM16 frames rather than WebRTC, and the platform exposes no model selection or declarative output schema. Scoring was therefore rebuilt on Bland's post-call /analyze endpoint, which returns a positional answer array, with a dedicated parser mapping those answers back to the rubric by index. The UI was redesigned as a light editorial layout: warm paper canvas, serif display type and hairline rules in place of stacked dark cards.
Bland Voice Agents — Interview & Sales Demo
Stack
Next.js 16React 19Tailwind CSS 4JavaScriptBland AI (@blandsdk/client)WebSocket / PCM16 Audio
Bland web agents are persistent server-side objects created via POST /v1/agents, so each role's rubric is baked into the agent prompt at creation time rather than passed inline per call as on Vapi.
Transport is a raw WebSocket streaming PCM16 frames with manual microphone capture through an AudioWorklet, not WebRTC — so the browser hook supplies its own AnalyserNode mic meter, since the SDK emits no volume events.
A setup script creates or updates all six agents idempotently, reading existing ids from the environment so re-running after a prompt change updates in place instead of orphaning duplicates.
The React hook preserves the same public surface as the Vapi implementation, so the call UI, transcript and report components were reused without modification.
Turn-Taking Debugging
The SDR agent initially answered sentence fragments: a 100ms interruption threshold meant a normal mid-sentence pause — "we use... spreadsheets, mostly" — was read as the end of a turn.
Raising the threshold to 700ms, above Bland's 500ms default, fixed it; a prospect describing a messy forecasting process pauses to think, and those pauses are not turn ends.
Interruptibility was deliberately left at the balanced default rather than lowered, since reducing it would make the agent ignore genuine interruptions — the wrong lever for the symptom.
The interviewer runs a much more patient 1100ms threshold, because a candidate pausing mid-answer must never be spoken over.
Rebuilding Structured Scoring
Bland web agents expose no declarative output schema, so the rubric instead drives a positional question list sent to POST /v1/calls/{id}/analyze after the call.
A dedicated parser module rebuilds that flat answer array into the shaped objects the scorecard renders, mapping answers back to competencies by index.
Each competency contributes a score question and an evidence question, preserving the rule that a score must be justified by something the candidate actually said.
Absent competencies resolve to zero and render as "n/a" rather than a low mark, keeping the calibration that a short interview should produce mostly zeros rather than polite threes.
Security & Interface Design
Bland provides no public browser key, so a server route exchanges the private API key for a single-use session token minted fresh for every call.
Agent ids are the only values exposed to the browser; an id alone cannot start a call without the server-held key.
The interface was redesigned as a light editorial layout — warm paper canvas, serif display headings, numbered entries separated by hairline rules — replacing the dark card-stacked theme.
Palette inversion was handled by remapping the colour scale at the theme level, flipping every usage across the component set from a single file rather than editing each call site.
Impact
Delivered the same two-agent voice product on a second platform, demonstrating the architectural trade-offs between an inline-config WebRTC platform and a persistent-agent WebSocket one.
Diagnosed and fixed a turn-taking fault by raising the silence threshold above the platform default, correctly rejecting the interruptibility setting as the wrong lever.
Preserved rubric-calibrated scoring on a platform with no structured-output support by rebuilding extraction on a positional post-call analysis endpoint.