DEV Community

Chao Shu Shen
Chao Shu Shen

Posted on

Why We Chose WebView Over SDK for In-App Customer Support

A Practical Engineering Perspective from Building ShenDesk

When integrating an online customer support system into a mobile app, I went through a long and sometimes frustrating process of technical exploration and trade-off analysis.

At the beginning, I was strongly attracted to several “technically ideal” options.
For example:

  • Letting app teams fully build their own UI while I only provide APIs, maximizing flexibility
  • Or integrating a native SDK to pursue the most “pure” native experience

On paper, these options look elegant.
In practice, as the project evolved, I gradually realized that solutions driven purely by technical ideals often fail to meet the complexity of real-world business scenarios.

This realization didn’t come from theory, but from feedback.

I had in-depth conversations with customers across more than a dozen industries, including e-commerce, education, SaaS, finance, and government-related organizations. Through real production deployments and continuous feedback loops, several critical decision factors became very clear.


Key Constraints That Actually Matter in Production

1. Time-to-launch is the primary bottleneck

Most teams want to launch customer support within one to two weeks, without disrupting their existing app flows.

“Can this be integrated quickly and painlessly?”
This question outweighed almost every other consideration.


2. UI consistency directly impacts user trust

Users expect the support interface to feel like a natural part of the app:

  • No jumping outside the app
  • No visually fragmented third-party windows

Even subtle inconsistencies in style or interaction can significantly degrade perceived quality and trust.


3. Functional completeness is non-negotiable

Modern customer support is not just about sending text messages.

Users expect:

  • Image and file uploads
  • AI bot integration
  • Queueing and agent transfer
  • Satisfaction ratings and feedback

These are no longer “advanced features”; they are baseline expectations.


4. Operational capacity is limited

Most engineering teams are small.

Maintaining a fully custom-built support module—especially real-time communication, state synchronization, and reconnection logic—quickly becomes a long-term operational burden rather than a one-time engineering effort.


5. Multi-platform UI becomes a hidden cost multiplier

If teams are asked to build and maintain their own chat UI across Android, iOS, and H5:

  • Development timelines effectively double
  • Maintenance complexity compounds over time

What looks like “maximum flexibility” at the beginning often turns into long-term technical debt.


The Strategy That Emerged

Based on these constraints, the technical direction became clear:

For most companies, the optimal path is a solution that is highly controllable, fast to integrate, functionally complete, and reusable across platforms.

Such a solution must provide enough flexibility—style customization, theme configuration, contextual parameters—while also relying on a mature and stable server-side foundation: queueing logic, agent assignment, chat history, notifications, and satisfaction surveys.

This philosophy is what guided the design of ShenDesk.

In the following sections, I’ll compare several common approaches for integrating customer support into mobile apps, and explain why we ultimately committed to WebView-based embedding, including real pitfalls we encountered and concrete implementation details.


SDK Integration or API + Custom UI?

Both SDK integration and API-driven custom UI can make sense in very specific, highly customized scenarios.

However, in real production environments, they often introduce significant hidden costs and risks.


Common Pitfalls of SDK-Based Integration

“Native SDK integration” is frequently marketed as the best possible user experience.
In actual engineering work, however, it often comes with underestimated complexity and long-term maintenance costs.

Below, I’ll break this down from three perspectives: development complexity, performance impact, and maintainability.


1. High integration complexity and strong platform coupling

SDKs typically require separate integration for Android and iOS, along with a non-trivial set of dependencies, permissions, and lifecycle hooks.

A small misconfiguration can easily result in runtime errors or crashes.

A common Android integration example:

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET"/>
<application>
    ...
    <activity android:name="com.sdk.chat.ChatActivity"
              android:theme="@style/SDKTheme"
              android:exported="true"/>
</application>
Enter fullscreen mode Exit fullscreen mode
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    ChatSDK.initialize(
        apiKey = "your_key",
        userId = user.id,
        context = this
    )
}
Enter fullscreen mode Exit fullscreen mode

Typical problems include:

  • SDK upgrades changing initialization parameters or permission requirements
  • Internal services or broadcasts interfering with host app behavior
  • Incomplete ProGuard/R8 configuration causing crashes in release builds

2. Noticeable binary size and performance overhead

Many third-party support SDKs bundle:

  • WebSocket clients
  • Image caching libraries
  • Local databases
  • Built-in UI templates, fonts, and animations

This often results in:

  • App size increases of 3–5 MB
  • Slower startup time, especially on low-end devices
  • Dependency conflicts and method count issues

3. Limited UI customization and fragmented UX

Most SDKs expose a closed, self-contained “support UI module.”

val intent = Intent(this, ChatSDK.getChatActivityClass())
startActivity(intent)
Enter fullscreen mode Exit fullscreen mode

You cannot embed it like a Fragment, nor can you control UI details at the DOM or layout level.

This leads to:

  • Visual inconsistency with the rest of the app
  • Restricted navigation and interaction patterns
  • Poor control over localization and theming

4. Opaque updates and difficult debugging

Because SDKs are maintained by third parties, their internal logic is largely invisible.

E/ChatSDK: WebSocket failed to connect.
E/ChatSDK: Internal message parser error.
Enter fullscreen mode Exit fullscreen mode

You cannot step into the source code, inspect state machines, or analyze message queues and retry logic.

In some cases, heavy obfuscation turns the SDK into a complete black box.


5. Weak integration with business context

Suppose you want your support system to understand what product or order the user is currently viewing and route the chat to the appropriate agent group.

With SDK-based integration, this is often extremely difficult:

  • Contextual data passing is limited or unsupported
  • Real-time business events cannot be injected
  • Server-side routing logic is not exposed
ChatSDK.sendMessage("{ \"type\": \"product\", \"id\": \"123456\" }")
Enter fullscreen mode Exit fullscreen mode

Structured messages like this are often rejected or silently reformatted, making advanced product-level features impossible.


The Trap of “API + Custom UI”

At first glance, building your own chat UI using APIs sounds flexible and empowering.
In reality, you quickly discover that a customer support system is not just a chat box, but a high-complexity asynchronous real-time system.

It involves message states, queueing, reconnection, file uploads, agent transfers, and satisfaction feedback—each with its own edge cases.


1. Message synchronization is deceptively complex

A real chat system must handle:

  • Sending / sent / failed states
  • Read receipts
  • Unread counters
  • Out-of-order messages
  • Deduplication
function sendMessage(content: string) {
    const msgId = generateClientMsgId();

    renderMessageLocally({ id: msgId, status: 'sending', content });

    sendToServer(content, msgId)
        .then(() => updateStatus(msgId, 'sent'))
        .catch(() => updateStatus(msgId, 'failed'));
}
Enter fullscreen mode Exit fullscreen mode

This logic breaks easily under network interruptions, retries, or mismatched acknowledgements.


2. Reconnection and message recovery are full of edge cases

Ensuring “no message loss” requires far more than reconnecting a WebSocket.

You need:

  • Last-message tracking
  • Incremental sync APIs
  • Deduplication and ordering guarantees
socket.onopen = () => {
    const lastTimestamp = getLastMessageTimestamp();
    fetch(`/api/messages/since?ts=${lastTimestamp}`).then(syncMessages);
}
Enter fullscreen mode Exit fullscreen mode

Clock drift, latency, and concurrent sends can quickly create inconsistent states.


3. UI state management easily spirals out of control

A chat UI is effectively a finite state machine:

  • Before session
  • Queueing
  • Active conversation
  • Finished

Network failures, agent transfers, or server restarts can trigger unexpected state transitions, and every edge case must be handled manually.


4. Critical logic lives on the server, not in the API docs

Agent routing, business hours, evaluation eligibility, rate limits—many behaviors are governed by server-side rules that APIs alone do not fully describe.

Triggering UI actions prematurely often leads to failed or confusing user experiences.


5. File uploads are surprisingly painful

Uploading images or files requires:

  • Storage signing (S3, OSS, etc.)
  • Validation, progress tracking, retries
  • Message linking and expiration handling

What looks simple quickly becomes one of the most error-prone parts of the system.


WebView Embedding: A Lightweight but Powerful Approach

After extensive evaluation, we chose WebView-based embedding as the default integration model for ShenDesk.

In this approach, the app embeds a hosted support page inside a WebView, while preserving UX continuity.

This allows us to achieve:

  • Faster integration
  • Lower client-side complexity
  • Greater customization flexibility
  • Stronger system-level control

Key Advantages

Low integration cost
Apps only need to open a WebView and pass basic parameters.

Easy updates
UI changes do not require app updates or store reviews.

Cross-platform consistency
One implementation works across iOS, Android, web, and other channels.

Context-aware integration
User identity and business context can be injected via URL parameters or cookies.


Final Thoughts

In theory, SDKs and fully custom UIs promise control and performance.
In practice, WebView offers a more balanced solution for most teams operating under real-world constraints.

This is not a shortcut—it is a deliberate engineering trade-off.


Wrapping up

ShenDesk is still evolving.

If you’ve ever built or deployed a real-time chat system, I’d genuinely love to hear your experience—
how you handled live updates, load balancing, or flexible deployment models in production.

Let’s compare notes.


If you’re curious

I’ve been building ShenDesk, a customer support chat system designed to run reliably
both online and on your own infrastructure.

You can try it for free, whether you prefer a hosted setup or self-hosting.

Feedback from developers interested in self-hosted systems, real-time communication,
and customer experience engineering is always welcome.


UI snapshots

Visitor side
Fast loading, no message loss

Visitor

Agent side
Reliable, feature-rich, built for real-world support work

Agent

Web admin panel

Web admin panel

Top comments (2)

Collapse
 
gabrieljemail profile image
Gabriel Jemail

That was a very long read... But asides that, I think your product is pretty good. I wish you luck with it.

Collapse
 
iccb1013 profile image
Chao Shu Shen

Thanks for reading, and thanks for the kind words.

I took some time to read through your personal site, and honestly, I’m impressed — getting into programming and actually building things at your age is awesome. I wish I had started that early.

Also, fun coincidence that we’re into some of the same games. That’s usually where a lot of interest in computers and software begins.

Appreciate the comment, and good luck with what you’re building.