Turns a scanned PDF into text you can search, copy and edit, written into a Google Doc page by page.
UsesExtend
Google DocsiLovePDF
Turn a multi-page scan into readable text
Give it one scanned PDF and the Google Doc it should go into, and run it. The text on each page is recognised in the language you name and added to your Doc in reading order: a heading with the file name and date, then each page under its own 'Page' heading. Paragraphs keep their breaks, and a table comes through row by row with its cells split by a vertical bar.
It is a transcript, not a summary: the words written are the words recognised, and a page where nothing could be read is counted rather than filled in. Nothing already in the Doc is changed, so one Doc can hold many scans. A long scan is done in parts, 40 pages at a time by default; if any page is skipped, fails to write or is left for a later run, an [INCOMPLETE] note at the end says so and which page to start from next, so a half-read scan is never mistaken for a whole one.
You need iLovePDF (which recognises the text), Extend (which lays it out) and Google Docs connected, the scan, a link to the Doc, and the language on the page; the wrong language is the usual reason a scan comes back as gibberish.
scanFile to blank.Set scanFile to blank.scanLanguage to eng.Set scanLanguage to eng.transcriptDocument to blank.Set transcriptDocument to blank.maxPages to 40.Set maxPages to 40.firstPage to 1.Set firstPage to 1.transcriptDocument and save it as documentLink.Trim transcriptDocument and save it as documentLink.transcriptId to documentLink.Set transcriptId to documentLink.documentLink contains /d/If documentLink contains /d/documentLink split by /d/ split by / and save it as transcriptId.Get the first item of the last item of documentLink split by /d/ split by / and save it as transcriptId.transcriptId is emptyIf transcriptId is emptymaxPages to the nearest integer and save it as pageLimit.Round maxPages to the nearest integer and save it as pageLimit.firstPage to the nearest integer and save it as startPage.Round firstPage to the nearest integer and save it as startPage.scanFile Save it as scanInfo.Read scanFile Save it as scanInfo.scanInfo.pages, or 0 if it is empty and save it as pageCount.Use scanInfo.pages, or 0 if it is empty and save it as pageCount.pageCount is less than 1If pageCount is less than 1startPage is greater than pageCountIf startPage is greater than pageCountpageCount pages, so there is nothing from page startPage on. Set 'firstPage' to 1, or to the page after the last one written, then run it again.Stop and report a problem: The scan has pageCount pages, so there is nothing from page startPage on. Set 'firstPage' to 1, or to the page after the last one written, then run it again.pagesAfterFirst to pageLimit minus 1.Set pagesAfterFirst to pageLimit minus 1.lastPage to startPage plus pagesAfterFirst.Set lastPage to startPage plus pagesAfterFirst.lastPage is greater than pageCountIf lastPage is greater than pageCountlastPage to pageCount.Change lastPage to pageCount.scanFile. Save it as searchableScan.Run OCR on scanFile. Save it as searchableScan.searchableScan.document_ref and save it as searchableRef.Trim searchableScan.document_ref and save it as searchableRef.searchableRef is null or searchableRef is emptyIf searchableRef is null or searchableRef is emptyreadPages.Parse a document. Save it as readPages.readPages.file_name and save it as scanTitle.Trim readPages.file_name and save it as scanTitle.scanTitle is null or scanTitle is emptyIf scanTitle is null or scanTitle is emptyscanTitle to Scanned document.Change scanTitle to Scanned document.pagesFound to 0.Set pagesFound to 0.pagesWritten to 0.Set pagesWritten to 0.pagesBlank to 0.Set pagesBlank to 0.pagesFailed to 0.Set pagesFailed to 0.lastWriteProblem to blank.Set lastWriteProblem to blank.today.Get today's date and save it as today.today readable as โMonday, November 2, 2026โ and save it as readDate.Make today readable as โMonday, November 2, 2026โ and save it as readDate.headingErrorIf a step below fails, save the error as headingErrortranscriptId. Save it as spacer.Add text to transcriptId. Save it as spacer.readDate' to transcriptId. Save it as scanHeading.Add the heading '@scanTitle, read on readDate' to transcriptId. Save it as scanHeading.headingError.message.Show in the output: The heading for this scan could not be written: headingError.message.page in readPages.chunks:For each page in readPages.chunks:pagesFound.Add 1 to pagesFound.pagesWritten is greater than or equal to pageLimitIf pagesWritten is greater than or equal to pageLimitpage.content and save it as pageText.Trim page.content and save it as pageText.pageText is null or pageText is emptyIf pageText is null or pageText is emptypagesBlank.Add 1 to pagesBlank.(?m)^[ \t]*#{1,6}[ \t]+|^[ \t]*\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)*\|?[ \t]*(?:\n|$)|^[ \t]*\|[ \t]*|[ \t]*\|[ \t]*$|\*\* with in pageText and save it as plainText.Replace the pattern (?m)^[ \t]*#{1,6}[ \t]+|^[ \t]*\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)*\|?[ \t]*(?:\n|$)|^[ \t]*\|[ \t]*|[ \t]*\|[ \t]*$|\*\* with in pageText and save it as plainText.pageErrorIf a step below fails, save the error as pageErrorpage.page_start' to transcriptId. Save it as pageHeading.Add the heading 'Page page.page_start' to transcriptId. Save it as pageHeading.transcriptId. Save it as pageWritten.Add text to transcriptId. Save it as pageWritten.plainTextpagesWritten.Add 1 to pagesWritten.pagesFailed.Add 1 to pagesFailed.lastWriteProblem to pageError.message.Change lastWriteProblem to pageError.message.page.page_start could not be written: pageError.message.Show in the output: Page page.page_start could not be written: pageError.message.pagesFound is 0If pagesFound is 0pagesWritten is 0 and pagesFailed is greater than 0If pagesWritten is 0 and pagesFailed is greater than 0lastWriteProblem). Check the link in 'transcriptDocument' and that your Google Docs connection can edit that Doc, then run it again.Stop and report a problem: No page could be written to your Google Doc (lastWriteProblem). Check the link in 'transcriptDocument' and that your Google Docs connection can edit that Doc, then run it again.pagesWritten is 0If pagesWritten is 0pagesMissing to pagesFound minus pagesWritten.Set pagesMissing to pagesFound minus pagesWritten.runSummary to pagesFound pages were read and pagesWritten were written. pagesBlank had no readable text and pagesFailed failed to write.Set runSummary to pagesFound pages were read and pagesWritten were written. pagesBlank had no readable text and pagesFailed failed to write.nextPage to lastPage plus 1.Set nextPage to lastPage plus 1.pagesLeftNote to blank.Set pagesLeftNote to blank.pageCount is greater than lastPageIf pageCount is greater than lastPagePages @nextPage to @pageCount of the scan were not read this time: set 'firstPage' to @nextPage and run it again to add them below, without repeating the pages... and save it as pagesLeftNote.Build the text Pages @nextPage to @pageCount of the scan were not read this time: set 'firstPage' to @nextPage and run it again to add them below, without repeating the pages... and save it as pagesLeftNote.pagesMissing is greater than 0 or pagesLeftNote isn't emptyIf pagesMissing is greater than 0 or pagesLeftNote isn't emptynoteErrorIf a step below fails, save the error as noteErrortranscriptId. Save it as noteWritten.Add text to transcriptId. Save it as noteWritten.[INCOMPLETE] runSummary@pagesLeftNote The pages above are not the whole scan.noteError.message.Show in the output: The incomplete-scan note could not be written: noteError.message.pagesFailed is greater than 0If pagesFailed is greater than 0runSummary plus pagesLeftNote.Stop and report a problem: runSummary plus pagesLeftNote.runSummary plus pagesLeftNote.Finish the run: runSummary plus pagesLeftNote.runSummary.Show in the output: runSummary.