All Products
Search
Document Center

Cloud Phone:Paste text in the Safari browser using the Web SDK

Last Updated:Apr 01, 2026

Safari's security policy blocks programmatic clipboard reads, triggering a native confirmation pop-up whenever the SDK tries to sync the local clipboard with the Cloud Phone. This guide shows you how to implement a custom clipboard dialog that lets users paste text into a Cloud Phone session without triggering that restriction.

Solution overview

  1. Add a custom clipboard button to your local client UI. Clicking the button opens a pop-up input box.

  2. The user pastes the content they want to send to the Cloud Phone into the pop-up input box.

  3. Clicking the Paste Now button in the pop-up synchronizes the content to both the Cloud Phone's clipboard and its active input field.

Configure the SDK parameters

Set the following parameters in connConfig before creating the session. Both are required for the custom clipboard flow to work.

ParameterValuePurpose
readClipboardDataByUserisSafari()Disables automatic clipboard reading by the SDK in Safari, giving you control over when clipboard data is sent
useCustomImetrueEnables the local Input Method Editor (IME), which is required to insert content into the Cloud Phone's active input field
// Detect Safari by checking the user agent
function isSafari() {
    return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
}

// Main control configuration
connConfig = {..., readClipboardDataByUser: isSafari(), useCustomIme: true};
var appInfo = {
    ...,
    connConfig: connConfig,
    ...
};
var sessionParam = {
    ...,
    appInfo: appInfo,
    ...
};
var wuyingSdk = Wuying.WebSDK;
session = wuyingSdk.createSession('appstream', sessionParam);

// Thumbnail configuration — also requires useCustomIme
this.thumbnail = new window.Wuying.ThumbnailSDK(
    {
        ...,
        connectionConfig: {
            useCustomIme: true,
        },
    },
    {
        onConnected: (data) => {
            this.thumbnail.session.getLocalConfig().setClipboardEnabled(true);
        },
        onDisConnected: (data) => {},
        onThumbnailData: (url) => {},
    }
);

Build the clipboard dialog

Add a clipboard button to your UI. When clicked, it opens a modal dialog where users can paste text and send it to the Cloud Phone.

Create the dialog

function showInput() {
    showCustomDialog();

    // Close the dialog when clicking outside it
    document.querySelector('.modal-overlay').addEventListener('click', function (e) {
        if (e.target === this) {
            closeModal();
        }
    });

    // Close the dialog on Escape
    document.addEventListener('keydown', function (e) {
        if (e.key === 'Escape') {
            closeModal();
        }
    });
}

function closeModal() {
    console.log('closeModal');
    const overlay = document.querySelector('.modal-overlay');
    if (overlay) {
        overlay.style.display = 'none';
        overlay.remove();
    }
}

function showCustomDialog() {
    // Create the modal overlay
    const overlay = document.createElement('div');
    overlay.className = 'modal-overlay';
    overlay.style.pointerEvents = 'all';
    overlay.style.zIndex = '9999';

    // Prevent keyboard events from reaching underlying UI elements
    const stopPropagation = function(e) {
        e.stopPropagation();
    };
    overlay.addEventListener('contextmenu', stopPropagation, true);
    overlay.addEventListener('keydown', stopPropagation, true);
    overlay.addEventListener('keyup', stopPropagation, true);
    overlay.addEventListener('keypress', stopPropagation, true);

    overlay.innerHTML = `
        <div class="modal">
            <div class="modal-header">
                <h2 class="modal-title">Clipboard</h2>
                <button class="close-btn" onclick="closeModal()">×</button>
            </div>
            <div class="input-container">
                <textarea
                    class="input-field"
                    placeholder="Enter content"
                    maxlength="500"
                ></textarea>
            </div>
            <button class="submit-btn" onclick="submitContent()">
                Paste Now
            </button>
        </div>
    `;

    document.body.appendChild(overlay);

    // Focus the textarea so keyboard events are captured immediately
    setTimeout(() => {
        const textarea = overlay.querySelector('.input-field');
        if (textarea) {
            textarea.focus();
        }
    }, 100);
}

Send the text to the Cloud Phone

When the user clicks Paste Now, the following functions validate the input and sync it to the Cloud Phone's clipboard and active input field.

function submitContent() {
    const content = document.querySelector('.input-field').value.trim();
    if (!content) {
        alert('Please enter content');
        return;
    }
    // Sync content to the Cloud Phone
    sendMsgToCloudPhoneOperation(content);
    closeModal();
}

function sendMsgToCloudPhoneOperation(msg) {
    // Main control session
    if (session) {
        session.setClipboardModule('sendClipboardDataToRemote', msg);
    }
    // Thumbnail sessions
    for (const [key, value] of thumbnailSDKMap) {
        console.log('thumbnail sendMsgToCloudPhoneOperation ', key, msg);
        value.thumbnail.session.getClipboardModule().sendClipboardDataToRemote(msg);
    }
}

Keyboard event handling

The modal overlay must intercept all keyboard events with stopPropagation before they reach other elements on the page. Without this, keystrokes typed inside the dialog are captured by the underlying UI instead of the textarea, breaking normal text input.

overlay.addEventListener('contextmenu', stopPropagation, true);
overlay.addEventListener('keydown', stopPropagation, true);
overlay.addEventListener('keyup', stopPropagation, true);
overlay.addEventListener('keypress', stopPropagation, true);