My main question is: do you mean the apps themselves, or the data of those apps? Because those are 2 pretty different things.
If you mean the apps themselves, I like this trick (but it requires the Android Developer tools):
# Write list of apps to file
adb shell "pm list packages" | sed 's/^package://' > installed_apps.txt
# Download and install each app in app list to device
while read -r app; do
suggested_version_code="$(curl "https://f-droid.org/api/v1/packages/${app}" | jq -r ".suggestedVersionCode")"
curl "https://f-droid.org/repo/${app}_${suggested_version_code}.apk" --output "${app}.apk"
adb install "${app}.apk"
done < installed_apps.txt
The data of apps is more complicated. In theory, any app that opts into Android’s backup framework should have its data backed up to and restored from Google, but I have no clue if Android always does that even when the app wasn’t installed from Google Play. What Android is doing there is kinda “magic”, Seedvault shows a nice GUI but Google’s implementation is very in the background to the point I don’t know if you can see if any data was backed up at all.