How to add footer page numbering in Google Docs via API using PHP?

I’m working on a project where I need to automatically add page numbers to the footer section of Google Docs documents using PHP and the Google Docs API. I’ve been searching for a solution but can’t figure out the right approach.

I found some documentation about pageNumberStart in the document style settings, so I tried implementing it like this:

$documentStyleRequest = new Google_Service_Docs_Request([
    'updateDocumentStyle' => [
        'documentStyle' => [
            'pageNumberStart' => 1,
        ],
        'fields' => 'pageNumberStart',
    ],
]);

However, this code doesn’t seem to work as expected. Nothing appears in the document footer.

Is there a proper method to programmatically insert page numbering into Google Docs footers using the API? I need the page numbers to show up at the bottom of each page automatically. Any working code examples or guidance would be really helpful.

This API is such a pain. I’ve wasted countless hours on Google Docs quirks.

The unicode workaround works sometimes but fails randomly. insertPageNumber is buggy as hell. Managing segment IDs and batch requests becomes a nightmare with multiple documents.

I fought this daily until I automated it properly. Now I use a Latenode workflow that handles everything.

It connects to Google Docs API, creates footers when needed, inserts page numbers with proper formatting, and catches all the errors that break manual PHP implementations.

Set it up once, trigger it from your PHP app with a webhook, and forget about API changes or segment ID headaches.

Saved me 10+ hours last month when Google changed something and killed my custom footer code. The workflow kept running like nothing happened.

Visit here for more info: https://latenode.com

pageNumberStart only sets the starting number - it doesn’t actually add page numbers to the footer. You need to insert a page break element.

Here’s what works:

// First, get the footer ID
$document = $service->documents->get($documentId);
$footerId = $document->getFooters()[0]->getFooterId();

// Then insert page number element
$requests = [
    new Google_Service_Docs_Request([
        'insertPageBreak' => [
            'location' => [
                'segmentId' => $footerId,
                'index' => 0
            ]
        ]
    ])
];

$batchUpdateRequest = new Google_Service_Docs_BatchUpdateDocumentRequest([
    'requests' => $requests
]);

$service->documents->batchUpdate($documentId, $batchUpdateRequest);

Honestly though, Google Docs API quirks get old fast. Been there with document automation.

Now I just use Latenode for all Google Docs stuff. Set up a workflow that takes your document ID, adds the footer with page numbering automatically, and handles all the API mess for you.

No more wrestling with segmentIds and batch requests. Just trigger it and get numbered pages.

Visit here for more info: https://latenode.com

Had this exact problem six months ago! The trick is handling footer creation and page numbers in separate batch requests. Most examples online combine them, which causes silent failures.

Here’s what works: check if a footer exists first, create one if needed, then add the page number. You have to let the document fully update between operations or the segmentId won’t be available.

// First batch - create footer
$createRequest = new Google_Service_Docs_BatchUpdateDocumentRequest([
    'requests' => [
        new Google_Service_Docs_Request([
            'createFooter' => ['type' => 'DEFAULT']
        ])
    ]
]);

$response = $service->documents->batchUpdate($documentId, $createRequest);
$footerId = $response->getReplies()[0]->getCreateFooter()->getFooterId();

// Second batch - insert page number
$numberRequest = new Google_Service_Docs_BatchUpdateDocumentRequest([
    'requests' => [
        new Google_Service_Docs_Request([
            'insertPageBreak' => [
                'location' => [
                    'segmentId' => $footerId,
                    'index' => 0
                ],
                'pageNumberType' => 'CURRENT'
            ]
        ])
    ]
]);

$service->documents->batchUpdate($documentId, $numberRequest);

This timing issue had me stuck for days until I split the requests. Also make sure your service account has edit permissions on the document - it’ll fail silently otherwise.

Your pageNumberStart approach won’t work - it only sets where numbering begins, not actually insert the page numbers. I hit this same wall building document automation for client reports.

Google’s API docs are misleading about footer page numbering. After testing multiple approaches, the most reliable method uses insertInlineObject with a PAGE_NUMBER object type instead of text insertion or page breaks.

// Get or create footer
$document = $service->documents->get($documentId);
$footers = $document->getFooters();
$footerId = $footers ? array_keys($footers)[0] : null;

if (!$footerId) {
    $createFooter = new Google_Service_Docs_Request([
        'createFooter' => ['type' => 'DEFAULT']
    ]);
    $response = $service->documents->batchUpdate($documentId, 
        new Google_Service_Docs_BatchUpdateDocumentRequest(['requests' => [$createFooter]]));
    $footerId = $response->getReplies()[0]->getCreateFooter()->getFooterId();
}

// Insert actual page number object
$pageNumberRequest = new Google_Service_Docs_Request([
    'insertInlineObject' => [
        'location' => [
            'segmentId' => $footerId,
            'index' => 0
        ],
        'inlineObject' => [
            'inlineObjectProperties' => [
                'embeddedObject' => [
                    'pageNumber' => ['type' => 'CURRENT']
                ]
            ]
        ]
    ]
]);

This creates proper dynamic page numbering that updates automatically across all pages. The inline object approach is way more stable than text placeholders or unicode tricks that break when Google updates their rendering engine.

The other answers are on the right track, but there’s actually a simpler way. I struggled with this same issue and found you just need to create a footer first, then insert the page number directly.

// Create footer if needed
$createFooterRequest = new Google_Service_Docs_Request([
    'createFooter' => [
        'type' => 'DEFAULT'
    ]
]);

// Get the footer segment ID from response
$response = $service->documents->batchUpdate($documentId, 
    new Google_Service_Docs_BatchUpdateDocumentRequest([
        'requests' => [$createFooterRequest]
    ])
);

$footerId = $response->getReplies()[0]->getCreateFooter()->getFooterId();

// Insert page number
$insertPageNumberRequest = new Google_Service_Docs_Request([
    'insertText' => [
        'location' => [
            'segmentId' => $footerId,
            'index' => 0
        ],
        'text' => "\u0001" // This is the page number placeholder
    ]
]);

The unicode character \u0001 automatically converts to dynamic page numbering. Way cleaner than using insertPageNumber, which I’ve found pretty unreliable.

had this exact problem last month - none of those solutions worked. You need insertPageBreak with pageNumberType set to footer. the unicode trick doesn’t work consistently anymore, think they changed something in the api. just grab your footer segment id and use the pageNumberType parameter instead of manually inserting text. saved me hours of debugging.

You’re close but missing a key step. You can’t just set the starting number - you need to actually insert the page number element into the footer. I fought with this same issue and here’s what finally worked.

Create or access your footer, then insert a page number element using insertText with a special placeholder. The trick is using CURRENT_PAGE element type:

$requests = [
    new Google_Service_Docs_Request([
        'insertText' => [
            'location' => [
                'segmentId' => $footerId,
                'index' => 0
            ],
            'text' => 'Page '
        ]
    ]),
    new Google_Service_Docs_Request([
        'insertPageNumber' => [
            'location' => [
                'segmentId' => $footerId,
                'index' => 5
            ]
        ]
    ])
];

Make sure you’ve got the footer ID first by checking if footers exist in your document structure. The insertPageNumber method is what actually creates the dynamic numbering that updates across all pages. Took me several tries because the docs are pretty unclear about the sequence.