Skip to main content

File Upload

The Lovina Chat SDK supports sending files (images, documents, audio, video) through the chat widget. Users can attach files via the paperclip button in the message composer.

Supported File Types and Size Limits

ConstraintLimit
Max files per message5
Max file size10 MB per file
Accepted typesimage/*, application/pdf, text/*, audio/*, video/*

Enabling / Disabling File Upload

File upload is enabled by default on web. To disable it:

window.lovinaSettings = {
fileUploadEnabled: false,
};

On native SDKs, the fileUploadEnabled flag is injected automatically based on WebView capabilities.

How It Works

User Experience

  1. Attach files — User taps the paperclip icon in the composer to open the native file picker.
  2. Preview — Selected files appear in a horizontal preview strip below the composer. Images show thumbnails; other files show a file icon with extension.
  3. Remove — Each preview has an "x" button to remove a file before sending.
  4. Send — User taps send. Files are uploaded, then the message is sent with attachment references.
  5. Display — Images render inline in the message bubble. Other files show as download links with file icon and size.

Upload Flow

The SDK uses a two-step upload flow:

1. User picks file(s) via native file picker
2. Files validated client-side (size + count limits)
3. Files staged in preview strip with blob URL thumbnails
4. On send:
a. A chat session is established first, if one doesn't already exist —
needed before any file can be uploaded
b. Upload each file: POST /sdk/chat/upload
→ Returns { attachment_id, file_url }
c. Send message: POST /sdk/chat/message
→ Body includes { message, attachment_ids: ["att-1", "att-2"] }
d. AI responds via SSE stream
5. On any upload failure: the whole message is marked failed (never sent
partially or text-only) and shows a Retry button. Files that already
uploaded successfully are not re-uploaded on retry.

Upload API

Step 1: Upload File

POST /sdk/chat/upload
Authorization: Bearer <websiteToken>
X-Session-Token: <session_token>
Content-Type: multipart/form-data

Fields:
session_id string Active session ID
file File The file to upload (max 10MB)

Response:

{
"attachment_id": "019078c3-d4e5-7f01-2345-678901abcdef",
"file_url": "https://storage.example.com/chat-attachments/.../document.pdf",
"file_name": "document.pdf",
"content_type": "application/pdf",
"size_in_bytes": 102400
}

Step 2: Send Message with Attachments

POST /sdk/chat/message
Authorization: Bearer <websiteToken>
Content-Type: application/json

{
"agent_config_id": "agent-xxx",
"message": "Here is the file",
"session_id": "session-xxx",
"attachment_ids": ["019078c3-d4e5-7f01-2345-678901abcdef"]
}

Attachment Object (in messages)

FieldTypeDescription
idstringUnique attachment ID
fileTypestringCategory: 'image', 'file', 'audio', 'video'
dataUrlstringURL to download/view the file
thumbUrlstringThumbnail URL (images only)
fileSizenumberFile size in bytes

Error Handling

ScenarioWhat User Sees
File > 10MBToast: "filename exceeds 10MB limit" — file rejected
> 5 filesToast: "Maximum 5 files allowed" — extras rejected
Upload fails (network, any file)Toast: "File upload failed" — the whole message (text and any other attachments) is marked failed, never sent
Upload fails (401)Toast: "Authentication expired"
Any upload failsThe message never sends — no partial or text-only fallback
RetryFailed messages show red bubble with Retry button. Files that already uploaded successfully are preserved and not re-uploaded.

Platform Support

PlatformStatusNotes
Web (all browsers)SupportedNative <input type="file"> with preview strip
Android WebViewSupportedonShowFileChooser + ActivityResultLauncher
iOS WKWebViewSupportedWKUIDelegate + UIDocumentPickerViewController
React NativeSupportedallowFileAccess props on WebView (v11+)
FlutterSupportedwebview_flutter v4+ handles natively
tip

File upload works on all platforms. The attach button is automatically hidden on platforms where file upload is not available (controlled by fileUploadEnabled flag injected by native SDKs).

How It Works on Each Platform

When a user taps the paperclip button, the widget triggers <input type="file">. Each platform handles this differently:

PlatformWhat OpensPermissions Needed
WebBrowser file dialogNone
AndroidSystem file picker (ACTION_GET_CONTENT)None (system picker handles its own)
iOSUIDocumentPickerViewControllerNone (document picker is sandboxed)
React NativeNative file picker via react-native-webviewNone
FlutterNative file picker via webview_flutterNone

:::warning Important for Native SDK Developers Android: Always call onReceiveValue() — even on cancel — or the WebView file input will hang permanently.

iOS: Always call completionHandler() — even on cancel — or WKWebView's file input silently breaks. :::

Permission Handling

File upload uses system file pickers on all platforms, which means no runtime permissions are required from the user. The OS handles file access internally.

However, there are edge cases:

ScenarioWhat HappensUser Sees
Android: no file manager appIntent.createChooser shows empty list"No apps can perform this action" dialog
iOS: iCloud file not downloadedOS downloads file firstiOS download progress indicator
iOS: camera / video captureThe WKWebView action sheet's "Take Photo or Video" option is reachable today, and needs NSCameraUsageDescription and NSMicrophoneUsageDescription in Info.plist -- omitting either one crashes the app on tap, it does not just deny the promptiOS permission prompt (or a crash if the keys are missing)
Android < 13: restricted storageSystem picker still worksNormal picker (system handles permissions)
WebView not configured<input type="file"> click does nothingAttach button hidden via fileUploadEnabled: false
User cancels pickeronReceiveValue(null) / completionHandler(nil) calledNothing happens, widget stays functional

:::info No permissions needed Unlike camera or microphone access, file upload via system pickers does not require any runtime permission prompts. The user simply picks a file from the system UI and the OS grants temporary read access to that specific file. :::