How does an SPV wallet use the headers that it downloads? My understanding is that an SPV wallet downloads "headers only". These headers are not enough to get a UTXO set, so it has to rely on another data source when it comes time to move bitcoin. If thats the case, then why does it even need the headers?
The SPV uses the Merkle Root in the header to verify transaction information full nodes provide. As a header refers to the previous block by hash, an SPV wallet can be somewhat sure that it has real blockchain information.

To hear about transactions relevant to it, an SPV requests to get information about any transactions involving a provided set of public keys (some of which actually belong to the SPV, but not all) from a full node. The full node does the look-up, then tells the SPV which blocks have transactions that are relevant for it. Now, the SPV doesn't have all transaction information, and if it only got transation C, it would have no way of knowing that this information is accurate. However, this is where the Merkle root comes into play, as a way to provide minimal information to verify the existence of transactions.

An Example:

Let's say this block X has three transactions A, B, and C; the transaction C being relevant to the SPV.

See the following picture for an overview how the Merkle Root is derived from the three transactions.



Now, if the full node would just provide C, the SPV would have no idea if the transaction is actually in block X, but by providing also H(A|B), the SPV can re-derive the Merkle root, allowing it to verify that C is in the block.

To read more about some shortcomings of SPV wallets please refer to Bitcoin's answer.