Import Handwritten List App

Hi Everyone. I created a sample app that will capture a handwritten list and then import each item as a record into a table. This is great for those or those who like to create handwritten lists while brainstorming a list of tasks, but want to easily convert them into itemized lists to track digitally.


Try it out with your own list or use this image as an example:

Because this sample app uses the API functionality, you will need to make a copy of the app to test out the functionality.

After you copy this sample you will need to update the API ID called in the workflow to your new application name. Change the App ID by selecting your app name from the dropdown menu.

How it works

This app was made with 3 tables. Input, Scan and Qty List.

List: Contains the list of tasks

Scan Data: Records the images of the handwritten lists

Qty List: Used to create a workflow that loops through each list of handwritten items. The max number in this list is the most items your app can handle. ie. If you table stops at 10, then your app will only generate 10 items then stop.

Next, Scan Data table columns were updated/added:

  1. OCR text column’s initial value was set to extract text from the Camera scan image.

  2. OCR Text List virtual column added: The formula converts the handwritten image into text, then cleans the text by removing characters such as ; , and then converts the text to a list if there is a line break in the text. The result is a list of items from the image.

  3. Qty List virtual column added: This column creates a list of numbers 1 to n based on how many items are in the OCR Text List.

  4. List Count column’s initial value is set to count the number items in the OCR Text List.

Creating the Looping Workflow

Now that the app can convert an handwritten list and store it as a list of text in a column, we need to create a way for the app to create a record from each item in the list.

An Adds_Only workflow that targets the Scan Data table is created and setup to with a webhook action. The webhook sends an Add row post to the List table. The body of the POST uses the Start function to loop through each number in the Qty List column creating a new record for each action. As a result we are able to keep track of each iteration of the loop and the workflow will stop once the loop reaches the max number in the Qty list column.


Lastly, since the workflows will happen on the server side I set an action to force a sync on save. This preserves the UX. If you do not do this the user will not see their list of items under the background sync completes.

There are several other small UX tweaks that were placed to prevent the user from doing things that would cause the OCR to break. For example, the OCR text function runs asynchronously in the app. This means unlike virtual columns which update as soon as data changes, OCR text can take up to 5 seconds to process. As a result, I placed some restrictions on form save to prevent users from saving a form with an empty OCR list.

Let me know if you have any questions. Please try it out and would love to see any improvements to this idea!


Interesting! I had a little trouble getting it to work, though. The scan seems to have successfully read my hand writing – in Japanese as well as in English!

Screen Shot 2020-06-27 at 09.16.18

In both languages, however, it didn’t always get the lines right.

Initially, I failed to follow the directions properly and to add my app ID, as you instructed. Perhaps that’s why I never got a proper menu, although I see that data has been written to my sheet.

It would be nice if there were a “this app ID” expression or function that we could use for sample apps like yours. I understand that most creators are producing apps that will be used on a paid plan. In such cases, only the creator needs to worry about the app ID. If, however, one wants to make a prototype app that many people can copy and use immediately, the lack of a “this app ID” expression could become a significant impediment to widespread adoption.

I understand that AppSheet is primarily interested in paid plans (which, of course, is your bread and butter as a business) but I think that increased support for free sample / prototype apps may help more people learn about the platform and thereby eventually increase the number of paying customers. Thanks!

1 Like

Nice! Thanks for sharing, @Rich.

I like how you’re looping through your own VC instead of a list of keys with the <<Start expression. Very creative.

I’ve often thought that myself when copying apps and modifying each version for a particular client. The AppName() would be useful, as well.

1 Like

Hi @Rich very cool thank you.
Why are you not using an Action to add all the List Items to the table? You would not have to force a sync.
I’m pretty sure there must be a reason why you choose workflow :blush:



I think everyone should be aware that OCR requires an enterprise package AND the “Machine learning” add on. This is not a “cheap” feature to put into production…

I think that in the tips and tricks section we should call out what plan package you need in order to roll it into production.


@Grant_Stead I’m using OCRTEXT() with different PRO Plans and it is working fine. You mean we need business plan?

According to their pricing page…


@Fabian you can certainly use an action to accomplish this too! Honestly, when I thought of this idea I got creatively locked into using a workflow for this demo and didn’t even consider an action. Now that you bring it up makes me want to update the app. :wink:


Thanks @Steve! Sorry for my late response. I’ve been away from the community for a while. I see in your article that, as Glinda might say, “we’ve always had the power.”

This is good news for me because I think I will use the function to make it possible for people who download my sample app to be able to view their images in the Google spreadsheet automatically:

=CONCATENATE(“”, ENCODEURL(“AppName-Account#”), “&tableName=”, ENCODEURL(“TableName”), “&fileName=”, ENCODEURL(+ImageColumnCell))

Thanks again!!


Thats’ cool @Kirk_Masden
Don’t forget to disable the “Require Image and File URL Signing” :slight_smile:


Right!! I just did that recently! :slight_smile: