You can check three factors in the
getblockchaininfo RPC call:
The result contains a count of the blocks in your chain, and the headers your node has received from peers. For a fully synchronized node, the number of blocks equals the number of headers.
Additionally, there is an
initialblockdownload boolean in the response, which will be set to false once the node has caught up with the main chain.