Record webcam videos in contact forms.
The client captures image frames with navigator.mediaDevices.getUserMedia(), streams them to the Videomail service over WebSocket, and receives an encoded video. No browser plugins are required. The package includes ESM, CommonJS, UMD, and TypeScript declaration builds.
- Live demo
- Storybook examples
- Installation
- Options
- API
- Form submissions
- Privacy and error reporting
- Stored videomail data
- Whitelist
- Browser compatibility
- Add-ons
- Notes
Try it at videomail-client.netlify.app.
There is a full version with all its features on videomail.io.
And there is more:
- https://wfdeaf.org/contact
- https://www.deaf.org.nz/contact
- And other sites using the package or its WordPress integration.
To check out some examples in your browser locally, just run these two commands:
npm installnpm run storybook
Storybook starts an HTTPS development server at https://localhost:8443 using the certificates in etc/ssl-certs.
npm install videomail-clientimport { VideomailClient } from "videomail-client";
const videomailClient = new VideomailClient({
whitelistKey: "your-whitelist-key",
});You can pass options to the VideomailClient constructor. See the annotated defaults in src/options.ts.
The defaults suit most integrations. Set whitelistKey when deploying on your own site; see Whitelist.
The examples in src/stories show common configurations.
new VideomailClient()videomailClient.on()videomailClient.show()videomailClient.hide()videomailClient.record()videomailClient.replay()videomailClient.startOver()videomailClient.getByAlias()videomailClient.getByKey()videomailClient.getThreadByAlias()videomailClient.getThreadByKey()videomailClient.unload()videomailClient.isDirty()videomailClient.isRecording()videomailClient.isBuilt()videomailClient.submit()videomailClient.getLogLines()videomailClient.setLimitSeconds()
The constructor accepts an optional options object:
const videomailClient = new VideomailClient({ whitelistKey: "my whitelist key" });VideomailClient provides an event-emitter-style API. on() returns an unsubscribe function:
videomailClient.on("FORM_READY", () => {
// The form is ready for recording.
});
videomailClient.on("SUBMITTED", ({ videomail, response }) => {
// Continue with application-specific submission handling.
});Check them out at src/types/events/index.ts
Some events include typed parameters exported by the package.
The client includes default visual error handling. Applications can also subscribe to the ERROR event for custom logging or recovery.
Videomail errors extend the native Error class and include additional diagnostic data.
Automatically fills the DOM with a form for video recording. By default the HTML element with the ID videomail will be filled, see options.
Starts recording without requiring the user to press the record button.
Adds a video player for the supplied videomail.
If replayParentElementId is supplied, the player is inserted into that element. Otherwise, the client uses or creates a replay container within the configured container.
Also note that, when the parent element already contains a video container like this
<video class="replay"></video>the client reuses it instead of creating another DOM element.
Resets the client and returns it to the ready state so the same instance can record another videomail.
Returns a videomail asynchronously for the given alias. You can obtain the alias from:
- The form submission to your own server has it under
videomail_aliasin the form body. - The
SUBMITTEDevent payload.
Returns a videomail asynchronously for its unique key.
Returns the videomail thread containing the given alias.
Returns the videomail thread containing the given key.
Manually unloads the webcam and all other internal event listeners.
Hides all the visuals (but does not unload anything).
Returns true when a video has been recorded but not submitted. This can be used before navigation to warn about an unsent recording.
Returns true while a video is being recorded.
Returns true after the client UI has been built and before it is unloaded.
Manually triggers submission when the client and form are valid. This is useful when another UI layer owns the visible submit control.
Returns the recently collected log lines when the configured logger supports collection.
Updates the recording time limit for subsequent recording activity.
The SUBMITTED event includes a videomail object. The exact response can evolve, but its shape follows the exported Videomail type. A shortened example is shown below:
{
"subject": "some subject",
"from": "some@sender.com",
"body": "A text body",
"recordingStats": {
"avgFps": 15.151515151515152,
"wantedFps": 15,
"avgInterval": 62.09090909090909,
"wantedInterval": 66.66666666666667,
"intervalSum": 683,
"framesCount": 11,
"videoType": "webm",
"waitingTime": 192
},
"width": 320,
"height": 240,
"whitelistKey": "videomail-client-demo",
"alias": "some-subject-183622500964",
"dateCreated": 1541130589811,
"url": "https://videomail.io/videomail/some-subject-150322500964",
"key": "11e8-de52-55ac2630-b22b-71959562a989",
"expiresAfter": 1541134189811,
"expiresAfterIso": "2018-11-02T04:49:49.811Z",
"expiresAfterServerPretty": "Nov 2, 2018, 5:49 PM",
"siteName": "Videomail Client Example",
"webm": "https://videomail.io/videomail/some-subject-183622500964/type/webm/",
"poster": "https://videomail.io/videomail/some-subject-183622500964/poster/",
"dateCreatedServerPretty": "Nov 2, 2018, 4:49 PM",
"replyUrl": "https://videomail.io/reply/some-subject-183622500964",
"sending": false,
"versions": {
"videomailClient": "15.7.14"
}
}You can also retrieve this data with videomailClient.getByKey().
By default, the client prevents the initial form submission and submits the videomail to the Videomail server first. After the server returns the alias and metadata, the client submits the original form.
If this does not work, verify that the configured selectors identify the form and its submit button:
selectors: {
formId: undefined,
submitButtonId: undefined,
submitButtonSelector: undefined,
}When these values are undefined (the defaults), the client detects the nearest form and a button with type="submit" automatically.
Enable submitWithVideomail to include videomail metadata in the submission to your server. Otherwise the form body contains the videomail alias, which can later be resolved with videomailClient.getByAlias(alias).
Recording sends webcam frames, and audio samples when enabled, to the configured Videomail service for encoding. The package does not provide offline recording.
The reportErrors option defaults to true. When an error occurs, the client can send the error, recent client logs, browser and operating-system details, page location, screen and orientation data, supported media constraints, and enumerated media-device information to the configured API. Set reportErrors: false if your privacy policy requires local-only error handling.
Examples work at https://localhost:8443 because localhost is allowed by the remote Videomail server. https://localhost and https://localhost:443 are also available for local development. Other origins require their own whitelist entry.
For a deployed domain, request access at videomail.io/whitelist. You will receive a whitelist key for the approved origins.
Recording requires a secure context (https:// or localhost) and support for navigator.mediaDevices.getUserMedia(), WebSocket, Canvas, and Web Audio when audio is enabled. Current evergreen desktop and mobile browsers are supported. Internet Explorer is not supported.
See Can I Use: Media Capture from DOM Elements and test the live demo in the browsers required by your integration.
There is also a Videomail WordPress add-on: https://wordpress.org/plugins/videomail-for-ninja-forms/
It extends the Ninja Forms form builder with a webcam input and submission integration.
A separate changelog is not maintained. Use git log or the commit history.
Videomail in the wild:
This is just the beginning. I will add a lot more over time.
Bear with me, there are lots of problems to crack, especially with the performance, audio part and some unit tests are missing. I do not want to waste too much time on perfection unless it's proven to work then I rewrite piece by piece.
These people helped inspire the project:
- Heath Sadler (Designer)
- Stefan Weber (Designer)
- Zack Best (Jurist)
- Sonia Pivac (Designer)
- Dominic Tarr (Boat Builder)
- Daniel Ly (Developer)
- Nicholas Buchanan (No idea)
- Kelvin Wong (Gamer)
- Isaac Johnston (Consultant)
They all deserve lots of love in return. Thank you so much.
The project prioritizes stability and bug fixes over large rewrites. Its implementation has evolved several times as browser media APIs and integration requirements have changed.
The primary goal is to make Sign Language easier to use in email and web forms.