diff --git a/mautrix_facebook/portal.py b/mautrix_facebook/portal.py
index 298d82c556c9504de87e0a6c257823fe1fe13ded..2c7c6c9466723d1e5b395bd84a4583307862cc92 100644
--- a/mautrix_facebook/portal.py
+++ b/mautrix_facebook/portal.py
@@ -14,10 +14,12 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 from typing import Dict, Optional, Tuple, Union, TYPE_CHECKING
-import aiohttp
 import asyncio
 import logging
 
+from yarl import URL
+import aiohttp
+
 from fbchat import (ThreadType, Thread, User as FBUser, Group as FBGroup, Page as FBPage,
                     Message as FBMessage)
 from mautrix.types import RoomID, EventType, ContentURI, MessageEventContent, EventID
@@ -47,27 +49,29 @@ class Portal:
     mxid: Optional[RoomID]
 
     name: str
-    photo: str
+    photo_id: str
     avatar_uri: ContentURI
 
-    messages_by_fbid: Dict[str, EventID]
-    messages_by_mxid: Dict[EventID, str]
+    messages_by_fbid: Dict[str, Optional[EventID]]
+    messages_by_mxid: Dict[EventID, Optional[str]]
 
     _main_intent: Optional[IntentAPI]
+    _create_room_lock: asyncio.Lock
 
     def __init__(self, fbid: str, fb_receiver: str, fb_type: ThreadType,
                  mxid: Optional[RoomID] = None,
-                 name: str = "", photo: str = "", avatar_uri: ContentURI = "") -> None:
+                 name: str = "", photo_id: str = "", avatar_uri: ContentURI = "") -> None:
         self.fbid = fbid
         self.fb_receiver = fb_receiver
         self.fb_type = fb_type
         self.mxid = mxid
 
         self.name = name
-        self.photo = photo
+        self.photo_id = photo_id
         self.avatar_uri = avatar_uri
 
         self._main_intent = None
+        self._create_room_lock = asyncio.Lock()
 
         self.messages_by_fbid = {}
         self.messages_by_mxid = {}
@@ -85,7 +89,7 @@ class Portal:
             "fb_receiver": self.fb_receiver,
             "mxid": self.mxid,
             "name": self.name,
-            "photo": self.photo,
+            "photo_id": self.photo_id,
             "avatar_uri": self.avatar_uri,
         }
 
@@ -93,7 +97,7 @@ class Portal:
     def from_dict(cls, data: Dict[str, str]) -> 'Portal':
         return cls(fbid=data["fbid"], fb_receiver=data["fb_receiver"],
                    fb_type=ThreadType(data["fb_type"]), mxid=RoomID(data["mxid"]),
-                   name=data["name"], photo=data["photo"],
+                   name=data["name"], photo_id=data["photo_id"],
                    avatar_uri=ContentURI(data["avatar_uri"]))
 
     @property
@@ -129,20 +133,31 @@ class Portal:
                              loop=self.loop)
         return info
 
+    @staticmethod
+    def _get_photo_id(url: str) -> str:
+        path = URL(url).path
+        return path[path.rfind("/") + 1:]
+
+    @staticmethod
+    async def _reupload_photo(url: str, client: IntentAPI) -> ContentURI:
+        async with aiohttp.ClientSession() as session:
+            resp = await session.get(url)
+            data = await resp.read()
+        return await client.upload_media(data)
+
     async def _update_name(self, name: str) -> None:
         if self.name != name:
             self.name = name
             if self.mxid and not self.is_direct:
                 await self.main_intent.set_room_name(self.mxid, self.name)
 
-    async def _update_photo(self, photo: str) -> None:
-        if self.photo != photo or len(self.avatar_uri) == 0:
-            self.photo = photo
+    async def _update_photo(self, photo_url: str) -> None:
+        photo_id = self._get_photo_id(photo_url)
+        print(photo_id, self.photo_id)
+        if self.photo_id != photo_id or len(self.avatar_uri) == 0:
+            self.photo_id = photo_id
             if self.mxid and not self.is_direct:
-                async with aiohttp.ClientSession() as session:
-                    resp = await session.get(self.photo)
-                    data = await resp.read()
-                self.avatar_uri = await self.main_intent.upload_media(data)
+                self.avatar_uri = await self._reupload_photo(photo_url, self.main_intent)
                 await self.main_intent.set_room_avatar(self.mxid, self.avatar_uri)
 
     async def _update_participants(self, source: 'u.User', info: ThreadClass) -> None:
@@ -158,9 +173,22 @@ class Portal:
         await asyncio.gather(*[puppet.intent.ensure_joined(self.mxid)
                                for puppet in puppets.values()])
 
-    async def create_matrix_room(self, source: 'u.User', info: Optional[Thread] = None) -> RoomID:
+    async def _update_matrix_room(self, source: 'u.User',
+                                  info: Optional[ThreadClass] = None) -> None:
+        await self.main_intent.invite_user(self.mxid, source.mxid)
+
+    async def create_matrix_room(self, source: 'u.User', info: Optional[ThreadClass] = None
+                                 ) -> RoomID:
+        if self.mxid:
+            await self._update_matrix_room(source, info)
+            return self.mxid
+        async with self._create_room_lock:
+            await self._create_matrix_room(source, info)
+
+    async def _create_matrix_room(self, source: 'u.User', info: Optional[ThreadClass] = None
+                                  ) -> RoomID:
         if self.mxid:
-            await self.main_intent.invite_user(self.mxid, source.mxid)
+            await self._update_matrix_room(source, info)
             return self.mxid
 
         info = await self.update_info(source=source, info=info)
@@ -176,7 +204,7 @@ class Portal:
                                                        invitees=[source.mxid])
         self.log.debug(f"Matrix room created: {self.mxid}")
         if not self.mxid:
-            raise Exception("Failed to create room")
+            raise Exception("Failed to create room: no mxid required")
         self.by_mxid[self.mxid] = self
         if not self.is_direct:
             await self._update_participants(source, info)
diff --git a/mautrix_facebook/puppet.py b/mautrix_facebook/puppet.py
index 31bfc23fdfc3bd36e535138abbc84f2d1d8342e1..bc1aad60b944437023f239fea7ec44d131863da8 100644
--- a/mautrix_facebook/puppet.py
+++ b/mautrix_facebook/puppet.py
@@ -23,7 +23,7 @@ from mautrix.types import UserID, ContentURI
 from mautrix.appservice import AppService, IntentAPI
 
 from .config import Config
-from . import user as u
+from . import user as u, portal as p
 
 if TYPE_CHECKING:
     from .context import Context
@@ -41,15 +41,15 @@ class Puppet:
 
     fbid: str
     name: str
-    photo: str
+    photo_id: str
     avatar_uri: ContentURI
 
     intent: IntentAPI
 
-    def __init__(self, fbid: str, name: str = "", photo: str = "", avatar_uri: ContentURI = ""):
+    def __init__(self, fbid: str, name: str = "", photo_id: str = "", avatar_uri: ContentURI = ""):
         self.fbid = fbid
         self.name = name
-        self.photo = photo
+        self.photo_id = photo_id
         self.avatar_uri = avatar_uri
 
         self.mxid = self.get_mxid_from_id(fbid)
@@ -61,13 +61,13 @@ class Puppet:
         return {
             "fbid": self.fbid,
             "name": self.name,
-            "photo": self.photo,
+            "photo_id": self.photo_id,
             "avatar_uri": self.avatar_uri,
         }
 
     @classmethod
     def from_dict(cls, data: Dict[str, str]) -> 'Puppet':
-        return cls(fbid=data["fbid"], name=data["name"], photo=data["photo"],
+        return cls(fbid=data["fbid"], name=data["name"], photo_id=data["photo_id"],
                    avatar_uri=ContentURI(data["avatar_uri"]))
 
     async def update_info(self, source: Optional['u.User'] = None, info: Optional[FBUser] = None
@@ -80,17 +80,17 @@ class Puppet:
 
     async def _update_name(self, info: FBUser) -> None:
         # TODO more precise name control
+        print(info.name, self.name)
         if info.name != self.name:
             self.name = info.name
             await self.intent.set_displayname(self.name)
 
-    async def _update_photo(self, photo: str) -> None:
-        if photo != self.photo or len(self.avatar_uri) == 0:
-            self.photo = photo
-            async with aiohttp.ClientSession() as session:
-                resp = await session.get(self.photo)
-                data = await resp.read()
-            self.avatar_uri = await self.intent.upload_media(data)
+    async def _update_photo(self, photo_url: str) -> None:
+        photo_id = p.Portal._get_photo_id(photo_url)
+        print(photo_id, self.photo_id)
+        if photo_id != self.photo_id or len(self.avatar_uri) == 0:
+            self.photo_id = photo_id
+            self.avatar_uri = await p.Portal._reupload_photo(photo_url, self.intent)
             await self.intent.set_avatar_url(self.avatar_uri)
 
     @classmethod
diff --git a/mautrix_facebook/user.py b/mautrix_facebook/user.py
index d95d859512fe4a349cf2c0218d8b0e782a25d278..5f4d738904ee857885a030c438d3c2fbf4b579d5 100644
--- a/mautrix_facebook/user.py
+++ b/mautrix_facebook/user.py
@@ -32,7 +32,6 @@ if TYPE_CHECKING:
 
 config: Config
 
-
 GREEN = "\u001b[32m"
 YELLOW = "\u001b[33m"
 MAGENTA = "\u001b[35m"
@@ -106,6 +105,10 @@ class User(Client):
 
     async def post_login(self) -> None:
         await self.sync_threads()
+        self.log.debug("Updating own puppet info")
+        own_info = (await self.fetchUserInfo(self.uid))[self.uid]
+        puppet = pu.Puppet.get(self.uid, create=True)
+        await puppet.update_info(source=self, info=own_info)
 
     async def sync_threads(self) -> None:
         try:
@@ -171,7 +174,7 @@ class User(Client):
     async def onMessage(self, mid: str = None, author_id: str = None, message: str = None,
                         message_object: Message = None, thread_id: str = None,
                         thread_type: ThreadType = ThreadType.USER, ts: int = None,
-                        metadata: Any = None, msg: Any = None):
+                        metadata: Any = None, msg: Any = None) -> None:
         """
         Called when the client is listening, and somebody sends a message