diff --git a/src/framework/Session.cpp b/src/framework/Session.cpp
--- a/src/framework/Session.cpp
+++ b/src/framework/Session.cpp
@@ -5189,10 +5189,18 @@ bool idSessionLocal::SaveGame( const char *saveName, saveType_t saveType ) {
 	tempDescriptionFile += ".tmp";
 
 	Session_RemoveStagedSaveFiles( tempGameFile, tempDescriptionFile, tempPreviewFile );
 
-	// Open savegame file
-	idFile *fileOut = fileSystem->OpenFileWrite( tempGameFile );
+	// WasmFS persists every permanent-file Write separately. Stage the complete
+	// payload in memory so a browser save reaches OPFS with one backend write.
+	idFile *fileOut = NULL;
+#if defined( __EMSCRIPTEN__ )
+	idFile_Memory *bufferedGameFile = new idFile_Memory( tempGameFile.c_str() );
+	bufferedGameFile->SetGranularity( 8 * 1024 * 1024 );
+	fileOut = bufferedGameFile;
+#else
+	fileOut = fileSystem->OpenFileWrite( tempGameFile );
+#endif
 	if ( fileOut == NULL ) {
 		common->Warning( "Failed to open save file '%s'\n", tempGameFile.c_str() );
 		Session_RestoreGeneratedSaveState( *this, generatedSaveName, saveType, previousLastQuicksave, previousLastCheckPoint );
 		syncNextGameFrame = true;
@@ -5312,10 +5320,33 @@ bool idSessionLocal::SaveGame( const char *saveName, saveType_t saveType ) {
 	}
 
 	game->SaveGame( fileOut, saveType );
 
-	// close the save game file
+	bool gameFileWritten = true;
+#if defined( __EMSCRIPTEN__ )
+	const int bufferedGameLength = bufferedGameFile->Length();
+	idFile *permanentGameFile = fileSystem->OpenFileWrite( tempGameFile );
+	if ( permanentGameFile == NULL ) {
+		gameFileWritten = false;
+	} else {
+		gameFileWritten = permanentGameFile->Write( bufferedGameFile->GetDataPtr(), bufferedGameLength ) == bufferedGameLength;
+		fileSystem->CloseFile( permanentGameFile );
+	}
+	fileSystem->CloseFile( fileOut );
+	if ( gameFileWritten ) {
+		common->Printf( "Browser save staged %d bytes in one filesystem write\n", bufferedGameLength );
+	}
+#else
 	fileSystem->CloseFile( fileOut );
+#endif
+	if ( !gameFileWritten ) {
+		common->Warning( "Failed to write staged savegame '%s'\n", tempGameFile.c_str() );
+		Session_RemoveStagedSaveFiles( tempGameFile, tempDescriptionFile, tempPreviewFile );
+		Session_RestoreGeneratedSaveState( *this, generatedSaveName, saveType, previousLastQuicksave, previousLastCheckPoint );
+		syncNextGameFrame = true;
+		soundSystem->SetMute( insideExecuteMapChange );
+		return false;
+	}
 
 	if ( !Session_ValidateStagedSaveGameHeader( tempGameFile ) ) {
 		common->Warning( "Staged savegame '%s' failed validation", tempGameFile.c_str() );
 		Session_RemoveStagedSaveFiles( tempGameFile, tempDescriptionFile, tempPreviewFile );
