diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index d6d9679da..972f1fe15 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -2548,6 +2548,10 @@ void ApiWrap::refreshFileReference(
 		request(MTPaccount_GetSavedRingtones(MTP_long(0)));
 	}, [&](Data::FileOriginPremiumPreviews data) {
 		request(MTPhelp_GetPremiumPromo());
+	}, [&](Data::FileOriginWebPage data) {
+		request(MTPmessages_GetWebPage(
+			MTP_string(data.url),
+			MTP_int(0)));
 	}, [&](Data::FileOriginStory data) {
 		request(MTPstories_GetStoriesByID(
 			_session->data().peer(data.peer)->input,
diff --git a/Telegram/SourceFiles/data/data_file_origin.cpp b/Telegram/SourceFiles/data/data_file_origin.cpp
index 9cac2ec4b..739873c3d 100644
--- a/Telegram/SourceFiles/data/data_file_origin.cpp
+++ b/Telegram/SourceFiles/data/data_file_origin.cpp
@@ -164,6 +164,9 @@ struct FileReferenceAccumulator {
 	void push(const MTPhelp_PremiumPromo &data) {
 		push(data.data().vvideos());
 	}
+	void push(const MTPmessages_WebPage &data) {
+		push(data.data().vwebpage());
+	}
 	void push(const MTPstories_Stories &data) {
 		push(data.data().vstories());
 	}
@@ -228,6 +231,10 @@ UpdatedFileReferences GetFileReferences(const MTPhelp_PremiumPromo &data) {
 	return GetFileReferencesHelper(data);
 }
 
+UpdatedFileReferences GetFileReferences(const MTPmessages_WebPage &data) {
+	return GetFileReferencesHelper(data);
+}
+
 UpdatedFileReferences GetFileReferences(const MTPstories_Stories &data) {
 	return GetFileReferencesHelper(data);
 }
diff --git a/Telegram/SourceFiles/data/data_file_origin.h b/Telegram/SourceFiles/data/data_file_origin.h
index 0e2e5e847..33e6a3f0d 100644
--- a/Telegram/SourceFiles/data/data_file_origin.h
+++ b/Telegram/SourceFiles/data/data_file_origin.h
@@ -121,6 +121,14 @@ struct FileOriginPremiumPreviews {
 	}
 };
 
+struct FileOriginWebPage {
+	QString url;
+
+	inline bool operator<(const FileOriginWebPage &other) const {
+		return url < other.url;
+	}
+};
+
 struct FileOrigin {
 	using Variant = std::variant<
 		v::null_t,
@@ -134,6 +142,7 @@ struct FileOrigin {
 		FileOriginTheme,
 		FileOriginRingtones,
 		FileOriginPremiumPreviews,
+		FileOriginWebPage,
 		FileOriginStory>;
 
 	FileOrigin() = default;
@@ -157,6 +166,8 @@ struct FileOrigin {
 	}
 	FileOrigin(FileOriginPremiumPreviews data) : data(data) {
 	}
+	FileOrigin(FileOriginWebPage data) : data(data) {
+	}
 	FileOrigin(FileOriginStory data) : data(data) {
 	}
 
@@ -208,6 +219,7 @@ UpdatedFileReferences GetFileReferences(const MTPTheme &data);
 UpdatedFileReferences GetFileReferences(
 	const MTPaccount_SavedRingtones &data);
 UpdatedFileReferences GetFileReferences(const MTPhelp_PremiumPromo &data);
+UpdatedFileReferences GetFileReferences(const MTPmessages_WebPage &data);
 UpdatedFileReferences GetFileReferences(const MTPstories_Stories &data);
 
 // Admin Log Event.
diff --git a/Telegram/SourceFiles/iv/iv_controller.cpp b/Telegram/SourceFiles/iv/iv_controller.cpp
index 20dc2b104..db69e9b97 100644
--- a/Telegram/SourceFiles/iv/iv_controller.cpp
+++ b/Telegram/SourceFiles/iv/iv_controller.cpp
@@ -281,10 +281,6 @@ void Controller::initControls() {
 	_subtitleLeft.stop();
 }
 
-bool Controller::showFast(const QString &url, const QString &hash) {
-	return false;
-}
-
 void Controller::show(
 		const QString &dataPath,
 		Prepared page,
diff --git a/Telegram/SourceFiles/iv/iv_controller.h b/Telegram/SourceFiles/iv/iv_controller.h
index 1cd563edf..76e53d6e5 100644
--- a/Telegram/SourceFiles/iv/iv_controller.h
+++ b/Telegram/SourceFiles/iv/iv_controller.h
@@ -65,7 +65,6 @@ public:
 		QString context;
 	};
 
-	[[nodiscard]] bool showFast(const QString &url, const QString &hash);
 	void show(
 		const QString &dataPath,
 		Prepared page,
diff --git a/Telegram/SourceFiles/iv/iv_data.cpp b/Telegram/SourceFiles/iv/iv_data.cpp
index dcfff77ba..9313c2fba 100644
--- a/Telegram/SourceFiles/iv/iv_data.cpp
+++ b/Telegram/SourceFiles/iv/iv_data.cpp
@@ -41,6 +41,7 @@ Geo GeoPointFromId(QByteArray data) {
 
 Data::Data(const MTPDwebPage &webpage, const MTPPage &page)
 : _source(std::make_unique<Source>(Source{
+	.pageId = webpage.vid().v,
 	.page = page,
 	.webpagePhoto = (webpage.vphoto()
 		? *webpage.vphoto()
diff --git a/Telegram/SourceFiles/iv/iv_instance.cpp b/Telegram/SourceFiles/iv/iv_instance.cpp
index 992eeec8f..845eaf394 100644
--- a/Telegram/SourceFiles/iv/iv_instance.cpp
+++ b/Telegram/SourceFiles/iv/iv_instance.cpp
@@ -124,8 +124,10 @@ private:
 	void showWindowed(Prepared result);
 	[[nodiscard]] ShareBoxResult shareBox(ShareBoxDescriptor &&descriptor);
 
-	void streamPhoto(PhotoId photoId, Webview::DataRequest request);
-	void streamFile(DocumentId documentId, Webview::DataRequest request);
+	[[nodiscard]] ::Data::FileOrigin fileOrigin(
+		not_null<WebPageData*> page) const;
+	void streamPhoto(QStringView idWithPageId, Webview::DataRequest request);
+	void streamFile(QStringView idWithPageId, Webview::DataRequest request);
 	void streamFile(FileStream &file, Webview::DataRequest request);
 	void processPartInFile(
 		FileStream &file,
@@ -414,9 +416,9 @@ void Shown::createController() {
 		const auto requested = QString::fromStdString(request.id);
 		const auto id = QStringView(requested);
 		if (id.startsWith(u"photo/")) {
-			streamPhoto(id.mid(6).toULongLong(), std::move(request));
+			streamPhoto(id.mid(6), std::move(request));
 		} else if (id.startsWith(u"document/"_q)) {
-			streamFile(id.mid(9).toULongLong(), std::move(request));
+			streamFile(id.mid(9), std::move(request));
 		} else if (id.startsWith(u"map/"_q)) {
 			streamMap(id.mid(4).toUtf8(), std::move(request));
 		} else if (id.startsWith(u"html/"_q)) {
@@ -437,16 +439,28 @@ void Shown::showWindowed(Prepared result) {
 		base::duplicate(_inChannelValues));
 }
 
-void Shown::streamPhoto(PhotoId photoId, Webview::DataRequest request) {
+::Data::FileOrigin Shown::fileOrigin(not_null<WebPageData*> page) const {
+	return ::Data::FileOriginWebPage{ page->url };
+}
+
+void Shown::streamPhoto(
+		QStringView idWithPageId,
+		Webview::DataRequest request) {
 	using namespace Data;
 
-	const auto photo = _session->data().photo(photoId);
-	if (photo->isNull()) {
+	const auto parts = idWithPageId.split('/');
+	if (parts.size() != 2) {
+		requestFail(std::move(request));
+		return;
+	}
+	const auto photo = _session->data().photo(parts[0].toULongLong());
+	const auto page = _session->data().webpage(parts[1].toULongLong());
+	if (photo->isNull() || page->url.isEmpty()) {
 		requestFail(std::move(request));
 		return;
 	}
 	const auto media = photo->createMediaView();
-	media->wanted(PhotoSize::Large, FileOrigin());
+	media->wanted(PhotoSize::Large, fileOrigin(page));
 	const auto check = [=] {
 		if (!media->loaded() && !media->owner()->failed(PhotoSize::Large)) {
 			return false;
@@ -466,17 +480,28 @@ void Shown::streamPhoto(PhotoId photoId, Webview::DataRequest request) {
 }
 
 void Shown::streamFile(
-		DocumentId documentId,
+		QStringView idWithPageId,
 		Webview::DataRequest request) {
 	using namespace Data;
 
+	const auto parts = idWithPageId.split('/');
+	if (parts.size() != 2) {
+		requestFail(std::move(request));
+		return;
+	}
+	const auto documentId = DocumentId(parts[0].toULongLong());
 	const auto i = _streams.find(documentId);
 	if (i != end(_streams)) {
 		streamFile(i->second, std::move(request));
 		return;
 	}
 	const auto document = _session->data().document(documentId);
-	auto loader = document->createStreamingLoader(FileOrigin(), false);
+	const auto page = _session->data().webpage(parts[1].toULongLong());
+	if (page->url.isEmpty()) {
+		requestFail(std::move(request));
+		return;
+	}
+	auto loader = document->createStreamingLoader(fileOrigin(page), false);
 	if (!loader) {
 		if (document->size >= Storage::kMaxFileInMemory) {
 			requestFail(std::move(request));
@@ -493,7 +518,7 @@ void Shown::streamFile(
 				file.media = std::move(media);
 				file.requests.push_back(std::move(request));
 				document->forceToCache(true);
-				document->save(::Data::FileOrigin(), QString());
+				document->save(fileOrigin(page), QString());
 			}
 		}
 		return;
@@ -747,9 +772,7 @@ bool Shown::active() const {
 }
 
 void Shown::moveTo(not_null<Data*> data, QString hash) {
-	if (!_controller || !_controller->showFast(data->id(), hash)) {
-		prepare(data, hash);
-	}
+	prepare(data, hash);
 }
 
 void Shown::update(not_null<Data*> data) {
diff --git a/Telegram/SourceFiles/iv/iv_prepare.cpp b/Telegram/SourceFiles/iv/iv_prepare.cpp
index 7d52a02ed..be089e105 100644
--- a/Telegram/SourceFiles/iv/iv_prepare.cpp
+++ b/Telegram/SourceFiles/iv/iv_prepare.cpp
@@ -160,6 +160,7 @@ private:
 		const QVector<MTPPageBlock> &items);
 
 	const Options _options;
+	const QByteArray _fileOriginPostfix;
 
 	base::flat_set<QByteArray> _resources;
 
@@ -202,7 +203,8 @@ private:
 }
 
 Parser::Parser(const Source &source, const Options &options)
-: _options(options) {
+: _options(options)
+, _fileOriginPostfix('/' + Number(source.pageId)) {
 	process(source);
 	_result.name = source.name;
 	_result.rtl = source.page.data().is_rtl();
@@ -1146,11 +1148,11 @@ Document Parser::documentById(uint64 id) {
 }
 
 QByteArray Parser::photoFullUrl(const Photo &photo) {
-	return resource("photo/" + Number(photo.id));
+	return resource("photo/" + Number(photo.id) + _fileOriginPostfix);
 }
 
 QByteArray Parser::documentFullUrl(const Document &document) {
-	return resource("document/" + Number(document.id));
+	return resource("document/" + Number(document.id) + _fileOriginPostfix);
 }
 
 QByteArray Parser::embedUrl(const QByteArray &html) {
diff --git a/Telegram/SourceFiles/iv/iv_prepare.h b/Telegram/SourceFiles/iv/iv_prepare.h
index dccc54202..a896c79e0 100644
--- a/Telegram/SourceFiles/iv/iv_prepare.h
+++ b/Telegram/SourceFiles/iv/iv_prepare.h
@@ -13,6 +13,7 @@ struct Options;
 struct Prepared;
 
 struct Source {
+	uint64 pageId = 0;
 	MTPPage page;
 	std::optional<MTPPhoto> webpagePhoto;
 	std::optional<MTPDocument> webpageDocument;