[SHARING] Lessons Learned Building My First Data Extraction Workflow

:waving_hand: Hi Community,

I’m Felix, and some of you might know me from the first workflow I’ve built and shared. My first project was an invoice data extraction automation that used Telegram as an interface. I could upload photos or PDFs, process them, and have the extracted data automatically added to a Google Sheet. That way, I could easily share an overview with my tax lawyer. You can find the workflow here: Automated expense tracking with Telegram, easybits & Google Sheets | n8n workflow template

Here’s a quick look at my tech stack:

  • n8n – workflow automation

  • easybits – document extraction API

  • Telegram Bot API

  • Google Sheets API

While building this workflow, I ran into a lot of small (and not-so-small) issues. I figured it might be useful to share them with the community, along with how I solved them. Your setup might be different, but hopefully, you’ll pick up some ideas.

Lesson 1: Google Sheets Formulas Keep Breaking?

Use OVERWRITE instead of INSERT_ROWS.
INSERT_ROWS shifts your data down and breaks your formulas. OVERWRITE appends without shifting, keeping everything intact.

Lesson 2: Numbers Stored as Text

My SUM formula kept returning zero. The numbers looked fine but were actually stored as text.
Fix: UsevalueInputOption=USER_ENTEREDinstead ofRAW.

Lesson 3: “No grid with id: 0” Error

This one drove me crazy. When working with existing sheets, the sheetId isn’t always 0.
Fix: Add a “Get Sheet Info” node to fetch the actual sheetId before formatting.

Lesson 4: Handle Both Photos AND PDFs

My first version only accepted photos. I forgot people also send invoices as PDFs.

{{ $json.body.message.photo || $json.body.message.document ? 'yes' : 'no' }}

Lesson 5: Dynamic Sheet Names

I had hardcoded “December_2025” in my URL and then wondered why September receipts went to the wrong sheet.
Fix: Use expressions to generate the sheet name dynamically from your data.

Lesson 6: Partial Reimbursement Rates

My employer covers 80% of phone bills. I added this into the workflow:

let eurRate = 1;
if (category === 'Mobile Phone') {
  eurRate = 0.8;
}
const eurAmount = totalAmount * eurRate;

Now the sheet shows the actual claimable amount.

Lesson 7: Handle Unknown Categories Gracefully

Not every receipt fits neatly into a category. Instead of defaulting to “Other,” the bot now asks:

“I could not determine the category. Please resend with a caption: Office Supplies, Marketing, Equipment…”

The user sends the photo again with a caption. Problem solved.

Lesson 8: Flexible Descriptions

Users want control. I built a simple caption format:

  1. Marketing → Category: Marketing, Details: Business Expense

  2. Marketing - Client gift → Category: Marketing, Details: Client gift

Simple separator, maximum flexibility.

Lesson 9: Apply Formatting AFTER Data Insertion

I pre-formatted cells with bold text. Then I added data, and formatting disappeared.
Lesson learned: Data insertion overwrites formatting. Always apply formatting after inserting data.

That’s it! Hopefully, some of these tips help you avoid the mistakes I made.

If you’ve run into similar problems or have questions, feel free to leave a comment – I’d love to hear your experiences!

How did you share the project with your client and did you use self hosting or cloud support cos I’m newbie to n8n automation who needs clear guidance so I may go the wrong way

1 Like

As far as I know, there are three main options:

1. Build in the client’s n8n account
The client signs up for n8n Cloud and invites you to build workflows directly. They own everything from day one, but they can see all work in progress. This works well if they want full transparency or plan to learn n8n themselves.

2. Build in your own account, then hand over
You build and test the workflow in your own n8n account, export it as JSON, and the client imports it into theirs. Credentials must be set up again. This is ideal for delivering a polished solution and reusing parts for other clients.

3. Managed service
You host and maintain the workflows yourself. The client interacts via a bot, email, or form and never logs into n8n. This works well for recurring revenue models but comes with ongoing maintenance responsibility.

Hope this helps. If you have further questions, feel free to reach out again.

Kindly share with me the procedure involved in Step 2 & 3

1 Like

Sure. For option 2, you would open your final workflow in n8n and click on the three dots in the top-right corner. There, you can select “Download”, which will download the workflow as a JSON file.

Your customer can then integrate this workflow into their own n8n account by creating a new workflow, clicking the three dots again, and choosing “Import from File…” to upload the JSON file.

The third option I mentioned applies, for example, if you build a workflow like this one that uses an interface (in this case, Telegram). In that scenario, you would only hand over the interface to your client. For this use case, that means the Telegram bot itself, so the client only interacts with the interface they need to use the automation.