Skip to main content

โ† Help

Embed Paint Ninja on your Website

Get help creating art with Paint Ninja.

Paint Ninja is a free online drawing app that lets you create art in your browser.

You can embed the Brush Ninja drawing app on your website. This is a great way to engage your users and get them to interact with your site. To embed the drawing app, just copy the code below and paste it into your website.

<script src="https://embed.brush.ninja/drawing.js"></script>
<brush-ninja-drawing></brush-ninja-drawing>

Properties

  • width - The width of the drawing app. Defaults to 100%.
  • height - The height of the drawing app. Defaults to 600px. Keep in mind the larger sizes may not fit on small screens (phones and tablets etc).
<brush-ninja-drawing
	width="800px"
	height="600px"
></brush-ninja-drawing>

Saving a drawing

The component can return the finished drawing as a PNG Blob. Your website can upload that blob to its own server, add it to a FormData request, or save it however it needs to.

<script src="https://embed.brush.ninja/drawing.js"></script>
<brush-ninja-drawing id="drawing"></brush-ninja-drawing>
<button id="save-drawing" type="button">Save drawing</button>

<script>
	const drawing = document.querySelector( '#drawing' );

	document.querySelector( '#save-drawing' ).addEventListener( 'click', async () => {
		const png = await drawing.exportPNG();
		const formData = new FormData();
		formData.append( 'drawing', png, 'my-drawing.png' );

		await fetch( '/save-drawing', { method: 'POST', body: formData } );
	} );
</script>

exportPNG() waits for the editor to load and resolves with a PNG Blob. It rejects if the editor cannot be reached or cannot create the image, so production code should handle errors in the usual way.

Saving an editable drawing

A PNG is ideal for sharing a finished picture, but it cannot be edited again. Use exportDocument() to save Paint Ninjaโ€™s layers and editable text. Store the returned Blob in your own database or file storage, then pass it back to loadDocument() when the user returns.

// Save an editable copy alongside, or instead of, a finished PNG.
const documentBlob = await drawing.exportDocument();
const formData = new FormData();
formData.append( 'drawing', documentBlob, 'my-drawing.brushninja' );
await fetch( '/save-editable-drawing', { method: 'POST', body: formData } );

// Later, retrieve the Blob from your own server and restore the editor.
const savedDocument = await fetch( '/my-drawing.brushninja' ).then( ( response ) => response.blob() );
await drawing.loadDocument( savedDocument );

Editable documents are JSON Blobs and may be larger than a PNG because they include every layer. loadDocument() accepts documents up to 50 MB and checks their size and layer limits before loading them.

Opening an image

To open an image supplied by your website, pass a Blob or File to loadImage(). This avoids asking Paint Ninja to fetch an arbitrary URL, keeps the drawing canvas exportable, and lets your own site control where files come from.

<input id="image-file" type="file" accept="image/png,image/jpeg,image/gif,image/webp">

<script>
	const drawing = document.querySelector( '#drawing' );

	document.querySelector( '#image-file' ).addEventListener( 'change', async ( event ) => {
		const file = event.target.files[ 0 ];

		if ( file ) {
			await drawing.loadImage( file );
		}
	} );
</script>

loadImage() accepts PNG, JPEG, GIF, and WebP files up to 20 MB. It resolves after the image is ready to edit.

Controlling the file toolbar

By default, the embedded editor behaves like the standalone app: New, Open, and Save work normally. A web app can change those three buttons without affecting drawing tools, layers, undo, redo, or zoom.

await drawing.setUI( {
	new: 'hidden',
	open: 'hidden',
	save: 'event',
} );

drawing.addEventListener( 'brush-ninja:action', async ( event ) => {
	if ( event.detail.action === 'save' ) {
		const documentBlob = await drawing.exportDocument();
		// Upload documentBlob to your own database here.
	}
} );

Each action may use one of these modes:

  • default โ€” use Paint Ninjaโ€™s normal action.
  • hidden โ€” do not show the button.
  • event โ€” show the button and dispatch brush-ninja:action instead of performing the normal action.

This is useful when the host app owns its own Save flow, file picker, account system, or navigation.

Optional local draft recovery

The standalone Paint Ninja app saves the current drawing in the browser. Embedded editors do not do this by default, because different embeds share the same iframe storage and must not restore each otherโ€™s work.

If local draft recovery is useful in your app, opt in with a stable key that identifies one of your own documents. Include your application, user, and drawing identifiers in the key rather than using a page URL.

await drawing.setPersistence( 'my-app:user-42:drawing-123' );

const wasRestored = await drawing.restoreSavedDocument();

if ( wasRestored ) {
	console.log( 'Restored the browser draft.' );
}

// Remove this one local draft, for example after a successful server save.
await drawing.clearSavedDocument();

This is browser-only draft recovery. Use exportDocument() and loadDocument() with your own server when you need a durable, account-backed saved drawing.

Events

The element also dispatches browser events if your page prefers to react to them:

  • brush-ninja:ready โ€” the editor is ready to receive API calls.
  • brush-ninja:export โ€” a PNG export finished; event.detail.blob is the PNG Blob.
  • brush-ninja:document-export โ€” an editable-document export finished; event.detail.blob is the document Blob.
  • brush-ninja:action โ€” a New, Open, or Save button configured with event was clicked; event.detail.action is the action name.
  • brush-ninja:error โ€” an API request failed; event.detail.error contains the error message.

Tips

  • The <script> tag can be placed anywhere on your page, but should only be added once.
  • The <brush-ninja-drawing> tag can be placed anywhere on your page, and any number of times. It will be replaced with the drawing app. Keep in mind that itโ€™s a javascript app and the more copies you include the slower your page will get.
  • You can pass classes to the <brush-ninja-drawing> tag to style it. For example, <brush-ninja-drawing class="my-class"></brush-ninja-drawing>. These classes will be applied to the iframe holding the app.

Tell me All About it!

If you use it then please do let me know on Mastodon, or Bluesky (or Contact me). I would love to see it in action!