diff --git a/src/config.ts b/src/config.ts
index 3ffefe278b..e327cb0ba5 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -89,6 +89,8 @@ type Source = {
 		public_key: string;
 		private_key: string;
 	};
+
+	google_maps_api_key: string;
 };
 
 /**
diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts
index c5f0d1d4dc..bf04588bcc 100644
--- a/src/web/app/common/mios.ts
+++ b/src/web/app/common/mios.ts
@@ -1,7 +1,7 @@
 import Vue from 'vue';
 import { EventEmitter } from 'eventemitter3';
 
-import { host, apiUrl, swPublickey, version, lang } from '../config';
+import { host, apiUrl, swPublickey, version, lang, googleMapsApiKey } from '../config';
 import Progress from './scripts/loading';
 import HomeStreamManager from './scripts/streaming/home-stream-manager';
 import DriveStreamManager from './scripts/streaming/drive-stream-manager';
@@ -170,8 +170,33 @@ export default class MiOS extends EventEmitter {
 			this.streams.messagingIndexStream = new MessagingIndexStreamManager(this.i);
 		});
 
-		// TODO: this global export is for debugging. so disable this if production build
-		(window as any).os = this;
+		//#region load google maps api
+		(window as any).initGoogleMaps = () => {
+			this.emit('init-google-maps');
+		};
+		const head = document.getElementsByTagName('head')[0];
+		const script = document.createElement('script');
+		script.setAttribute('src', `https://maps.googleapis.com/maps/api/js?key=${googleMapsApiKey}&callback=initGoogleMaps`);
+		script.setAttribute('async', 'true');
+		script.setAttribute('defer', 'true');
+		head.appendChild(script);
+		//#endregion
+
+		if (this.debug) {
+			(window as any).os = this;
+		}
+	}
+
+	public getGoogleMaps() {
+		return new Promise((res, rej) => {
+			if ((window as any).google && (window as any).google.maps) {
+				res((window as any).google.maps);
+			} else {
+				this.once('init-google-maps', () => {
+					res((window as any).google.maps);
+				});
+			}
+		});
 	}
 
 	public log(...args) {
diff --git a/src/web/app/config.ts b/src/web/app/config.ts
index b51279192c..24158c3aed 100644
--- a/src/web/app/config.ts
+++ b/src/web/app/config.ts
@@ -13,6 +13,7 @@ declare const _THEME_COLOR_: string;
 declare const _COPYRIGHT_: string;
 declare const _VERSION_: string;
 declare const _LICENSE_: string;
+declare const _GOOGLE_MAPS_API_KEY_: string;
 
 export const host = _HOST_;
 export const url = _URL_;
@@ -29,3 +30,4 @@ export const themeColor = _THEME_COLOR_;
 export const copyright = _COPYRIGHT_;
 export const version = _VERSION_;
 export const license = _LICENSE_;
+export const googleMapsApiKey = _GOOGLE_MAPS_API_KEY_;
diff --git a/src/web/app/desktop/views/components/post-detail.vue b/src/web/app/desktop/views/components/post-detail.vue
index 32d401351d..fdf97282b3 100644
--- a/src/web/app/desktop/views/components/post-detail.vue
+++ b/src/web/app/desktop/views/components/post-detail.vue
@@ -39,14 +39,16 @@
 		</header>
 		<div class="body">
 			<mk-post-html :class="$style.text" v-if="p.ast" :ast="p.ast" :i="os.i"/>
-			<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 			<div class="media" v-if="p.media">
 				<mk-images :images="p.media"/>
 			</div>
 			<mk-poll v-if="p.poll" :post="p"/>
+			<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 			<div class="tags" v-if="p.tags && p.tags.length > 0">
 				<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link>
 			</div>
+			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.latitude},${p.geo.longitude}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+			<div class="map" v-if="p.geo" ref="map"></div>
 		</div>
 		<footer>
 			<mk-reactions-viewer :post="p"/>
@@ -137,6 +139,21 @@ export default Vue.extend({
 				this.replies = replies;
 			});
 		}
+
+		// Draw map
+		if (this.p.geo) {
+			(this as any).os.getGoogleMaps().then(maps => {
+				const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
+				const map = new maps.Map(this.$refs.map, {
+					center: uluru,
+					zoom: 15
+				});
+				new maps.Marker({
+					position: uluru,
+					map: map
+				});
+			});
+		}
 	},
 	methods: {
 		fetchContext() {
@@ -308,6 +325,15 @@ export default Vue.extend({
 		> .body
 			padding 8px 0
 
+			> .location
+				margin 4px 0
+				font-size 12px
+				color #ccc
+
+			> .map
+				width 100%
+				height 300px
+
 			> .mk-url-preview
 				margin-top 8px
 
diff --git a/src/web/app/desktop/views/components/posts.post.vue b/src/web/app/desktop/views/components/posts.post.vue
index e73f1445ee..11bf3c3b57 100644
--- a/src/web/app/desktop/views/components/posts.post.vue
+++ b/src/web/app/desktop/views/components/posts.post.vue
@@ -49,6 +49,7 @@
 					<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link>
 				</div>
 				<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.latitude},${p.geo.longitude}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+				<div class="map" v-if="p.geo" ref="map"></div>
 				<div class="repost" v-if="p.repost">
 					<mk-post-preview class="repost" :post="p.repost"/>
 				</div>
@@ -158,6 +159,21 @@ export default Vue.extend({
 		if ((this as any).os.isSignedIn) {
 			this.connection.on('_connected_', this.onStreamConnected);
 		}
+
+		// Draw map
+		if (this.p.geo) {
+			(this as any).os.getGoogleMaps().then(maps => {
+				const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
+				const map = new maps.Map(this.$refs.map, {
+					center: uluru,
+					zoom: 15
+				});
+				new maps.Marker({
+					position: uluru,
+					map: map
+				});
+			});
+		}
 	},
 	beforeDestroy() {
 		this.decapture(true);
@@ -447,6 +463,10 @@ export default Vue.extend({
 					font-size 12px
 					color #ccc
 
+				> .map
+					width 100%
+					height 300px
+
 				> .tags
 					margin 4px 0 0 0
 
diff --git a/src/web/app/mobile/views/components/post-detail.vue b/src/web/app/mobile/views/components/post-detail.vue
index 7e6217f604..554cfa07a0 100644
--- a/src/web/app/mobile/views/components/post-detail.vue
+++ b/src/web/app/mobile/views/components/post-detail.vue
@@ -42,11 +42,13 @@
 			<div class="tags" v-if="p.tags && p.tags.length > 0">
 				<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link>
 			</div>
-			<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 			<div class="media" v-if="p.media">
 				<mk-images :images="p.media"/>
 			</div>
 			<mk-poll v-if="p.poll" :post="p"/>
+			<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
+			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.latitude},${p.geo.longitude}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+			<div class="map" v-if="p.geo" ref="map"></div>
 		</div>
 		<router-link class="time" :to="`/${p.user.username}/${p.id}`">
 			<mk-time :time="p.created_at" mode="detail"/>
@@ -133,6 +135,21 @@ export default Vue.extend({
 				this.replies = replies;
 			});
 		}
+
+		// Draw map
+		if (this.p.geo) {
+			(this as any).os.getGoogleMaps().then(maps => {
+				const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
+				const map = new maps.Map(this.$refs.map, {
+					center: uluru,
+					zoom: 15
+				});
+				new maps.Marker({
+					position: uluru,
+					map: map
+				});
+			});
+		}
 	},
 	methods: {
 		fetchContext() {
@@ -309,6 +326,15 @@ export default Vue.extend({
 		> .body
 			padding 8px 0
 
+			> .location
+				margin 4px 0
+				font-size 12px
+				color #ccc
+
+			> .map
+				width 100%
+				height 200px
+
 			> .mk-url-preview
 				margin-top 8px
 
diff --git a/src/web/app/mobile/views/components/post.vue b/src/web/app/mobile/views/components/post.vue
index 7cd6393fe4..2026fe53b0 100644
--- a/src/web/app/mobile/views/components/post.vue
+++ b/src/web/app/mobile/views/components/post.vue
@@ -49,6 +49,7 @@
 				</div>
 				<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 				<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.latitude},${p.geo.longitude}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+				<div class="map" v-if="p.geo" ref="map"></div>
 				<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
 				<div class="repost" v-if="p.repost">
 					<mk-post-preview class="repost" :post="p.repost"/>
@@ -133,6 +134,21 @@ export default Vue.extend({
 		if ((this as any).os.isSignedIn) {
 			this.connection.on('_connected_', this.onStreamConnected);
 		}
+
+		// Draw map
+		if (this.p.geo) {
+			(this as any).os.getGoogleMaps().then(maps => {
+				const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
+				const map = new maps.Map(this.$refs.map, {
+					center: uluru,
+					zoom: 15
+				});
+				new maps.Marker({
+					position: uluru,
+					map: map
+				});
+			});
+		}
 	},
 	beforeDestroy() {
 		this.decapture(true);
@@ -428,6 +444,10 @@ export default Vue.extend({
 					font-size 12px
 					color #ccc
 
+				> .map
+					width 100%
+					height 200px
+
 				> .app
 					font-size 12px
 					color #ccc
diff --git a/webpack/plugins/consts.ts b/webpack/plugins/consts.ts
index cb9ba8e86f..6435893234 100644
--- a/webpack/plugins/consts.ts
+++ b/webpack/plugins/consts.ts
@@ -27,7 +27,8 @@ export default lang => {
 		_LANG_: lang,
 		_HOST_: config.host,
 		_URL_: config.url,
-		_LICENSE_: licenseHtml
+		_LICENSE_: licenseHtml,
+		_GOOGLE_MAPS_API_KEY_: config.google_maps_api_key
 	};
 
 	const _consts = {};