Easily Print Receipts Without The Use Of Third-Party Software / Platform

Hi Bubblers!

Printing receipts in Bubble can be quite a hassle and expensive. You would need to use third party software or platforms such as JSPrintManager, QZ Tray, Print Node, etc.

These platforms are quite pricey. They are often priced at $500 minimum and would be more expensive if you’d need to integrate it to multiple web servers. Some have monthly pricing which is cheaper but you’d be limited in the number of documents you could print.

Integrating these software or platforms can also be quite hard especially if you’re not technical. You’d need to use JavaScript and ESC/POS commands.

I’d like to share this cheap and easy workaround to print receipts.

Here’s what you need:

Steps On How To Print Receipts

  1. Create your receipt design on a word document.
    Make sure to set the page’s size to your receipt’s width in inches.
  2. Copy everything in your word document and head over to https://wordtohtml.net/
  3. Paste what you copied on the visual editor
  4. Copy the HTML on the right side
  5. In your bubble app, head over to the page where you would need to print the receipts and add the Print Toolkit Element from the Print Pro Plugin
  6. Assuming you’ve finalized which button should be clicked to print a receipt, add the plugin action Print HTML Template PrintToolkit A
  7. Paste the copied HTML from https://wordtohtml.net/ to the Custom HTML Template input
  8. Let’s add the dynamic values! Head back to your word document and copy the text that you would need to replace for dynamic values.
  9. Find the text that you would need to replace in the HTML by pressing CTRL + F on your keyboard
  10. Highlight the text and add your dynamic data

Repeat steps 8 to 10 if you have more texts to replace with dynamic data

Q: But I have a table with multiple rows. How should I print that? :cold_sweat:

Here’s how you would add dynamic data to your tables:

Assuming you made tables in your word document, simply head over to the table row <tr> tag on the HTML and Cut that out.

If you’re having trouble looking for this table element, you could also head back to your word document and copy the text on the first row and column. Search for it again by pressing Control + F on your keyboard

After cutting the table row element, add your dynamic data source. This should be a list either from a a search or repeating group and format it as a text.

I would, however, suggest to use a repeating group instead of searching for the items since it might cause a timeout especially for long lists.

It should look like this

In the format as text expression, paste the table row element code that you cut a while ago in the content to show per list item input. It should look like this:

Replace each column with dynamic data like what we did on steps 8 - 10

  1. Let’s add the dynamic values! Head back to your word document and copy the text that you would need to replace for dynamic values.
  2. Find the text that you would need to replace in the HTML by pressing CTRL + F on your keyboard
  3. Highlight the text and add your dynamic data

If we’re printing using bond papers only, this should be good to go since by default, the page size is a4 or depends entirely on your default printer’s settings.

So how should structure the html to be small i.e. the size of a thermal paper? :thinking:

We do that using CSS! :star_struck:

In the HTML template, simply add this CSS:

@media print {
  @page {
    size: 58mm; /* the width of your thermal paper */
    margin: 0mm; /* you can set the margins to 0 if you don't need them */
  body {
    margin: 0;

And voila! Your receipt is now ready to print!

Whenever this workflow is triggered, it would open the browser’s print dialog!

Don’t worry about the empty white spaces below. Thermal printers amazingly disregard empty sections and just print the text that you need.

Here are loom videos on how to do steps 1-10:

Video 1
Video 2
Video 3

Huge thanks and credits to @adunniola for making steps 1 - 10 and even making a loom video about it! You’re awesome :heart_eyes:

Disclaimer: This workaround is only for printing simple receipts. If you’re using or planning to use other hardware devices such as cash registers, weighing scales, and the like, this workaround is NOT FOR YOU. Those require ESC / POS commands.

If by any chance, you’ll use those. I would highly recommend reading @BrianHenderson’s forum threads and comments about POS Printing. He’s a rockstar in that field :saluting_face:

Here’s a great thread about ESC / POS Printing

Hope this helps!

Let’s get those receipts printing!!! :money_mouth_face:


Could there be an XSS exploit here? If the user can specify the product names etc, might be a good idea to find and replace <script>

At least for our use case, that’s unlikely to happen since we’re using this workaround for an internal tool.

But for other use cases, I’m wondering how that could be possible.

Users would only input the product name via an input element in bubble. So it would only be a text which would then just be referenced in the HTML template Assuming they typed a malicious script.

There would be no way to inject the malicious script to our app / bubble’s system (I think) since this workaround isn’t using any Javascript except for the plugin. The HTML template plugin action simply references to the text in the DB.

If by any chance, users could simply input a malicious script, wouldn’t that entirely make all the input elements risky?

Assuming cross site scripting is possible, we can’t also modify the script since we can’t edit the plugin’s code.

No, displaying user inputs anywhere is fine, but the HTML element isn’t protected. Found this from Josh (albeit 8 years ago):

Don’t know how it might interact with the plugin - maybe it would just throw an error. But it sounds like it doesn’t matter for you as it’s an internal tool :slight_smile:

1 Like

This is valuable information @georgecollier

Thank you so much! Will update this thread if ever I encounter or hear anything related to that issue in this workaround.