It is not really possible to serialize workflow state when it is blocked synchronously on an API call. It also could be prohibitively expensive to ship the whole state on every update in some cases. Another problem with serialization is that in Go, for example the majority of data structures are not serializable if they contain private fields.
So serialization is not used to recover state. Instead, event sourcing is used. All results of external API calls (which must be done only through APIs provided by the Temporal SDK) are recorded in the event history. Then on recovery, the workflow code is replayed from the beginning and all API call results are given from the recorded events. Assuming that the workflow code is deterministic it ends up in exactly the same state as it was before. This way only input and output arguments of activities, child workflows, and other Temporal SDK API calls have to be serializable.
This presentation contains step by step explanation of the process starting from 14:55.