Index: ow/models/root.py
===================================================================
--- ow/models/root.py	(revision 4226ce04db48dcae8cd2a215b935d6ed69eca77e)
+++ ow/models/root.py	(revision bddf042a37868bbfc94dcfcb533ec5ca46f2796e)
@@ -11,4 +11,5 @@
     get_catalog,
     install_catalog,
+    update_indexes,
     reindex_object,
     remove_from_catalog,
@@ -40,7 +41,11 @@
         indexes = {
             'email': CatalogFieldIndex('email'),
+            'nickname': CatalogFieldIndex('nickname'),
             'sport': CatalogFieldIndex('sport'),
         }
         return indexes
+
+    def _update_indexes(self):
+        return update_indexes(self.catalog, self._get_catalog_indexes())
 
     def reindex(self, obj):
@@ -77,4 +82,13 @@
             # the catalog will return all users
             res = self.query(Eq('email', email))
+            if res:
+                return next(res)
+        return None
+
+    def get_user_by_nickname(self, nickname):
+        if nickname is not None:
+            # for some reason, when searching for None
+            # the catalog will return all users
+            res = self.query(Eq('nickname', nickname))
             if res:
                 return next(res)
Index: ow/templates/profile.pt
===================================================================
--- ow/templates/profile.pt	(revision 4226ce04db48dcae8cd2a215b935d6ed69eca77e)
+++ ow/templates/profile.pt	(revision bddf042a37868bbfc94dcfcb533ec5ca46f2796e)
@@ -17,28 +17,31 @@
       <div class="user-profile-account">
         <div>
-          <tal:c tal:condition="getattr(context, 'picture', None)">
-            <img tal:attributes="src request.resource_path(context, 'picture')"
+          <tal:c tal:condition="getattr(user, 'picture', None)">
+            <img tal:attributes="src request.resource_path(user, 'picture')"
                  width="450" />
           </tal:c>
           <div>
             <h2>
-                <tal:fullname tal:content="context.fullname"></tal:fullname>
+                <tal:fullname tal:content="user.fullname"></tal:fullname>
             </h2>
             <p>
-              <tal:has-nickname tal:condition="context.nickname">
-                  <tal:nickname tal:content="context.nickname"></tal:nickname>
-              </tal:has-nickname> |
-              <span><tal:email tal:content="context.email"></tal:email></span>
+              <tal:has-nickname tal:condition="user.nickname">
+                <a href=""
+                   tal:attributes="href request.resource_url(request.root, 'profile', user.nickname)"
+                   tal:content="request.resource_url(request.root, 'profile', user.nickname)">
+                </a> |
+              </tal:has-nickname>
+              <span><tal:email tal:content="user.email"></tal:email></span>
             </p>
             <div class="profile-bio">
-              <p tal:repeat="paragraph getattr(context, 'bio', '').split('\n')"
+              <p tal:repeat="paragraph getattr(user, 'bio', '').split('\n')"
                  tal:content="paragraph"></p>
             </div>
             <ul class="workout-options">
               <li><a href=""
-                     tal:attributes="href request.resource_url(context, 'edit')"
+                     tal:attributes="href request.resource_url(user, 'edit')"
                      i18n:translate="">edit profile</a></li>
               <li><a href=""
-                     tal:attributes="href request.resource_url(context, 'passwd')"
+                     tal:attributes="href request.resource_url(user, 'passwd')"
                      i18n:translate="">change password</a></li>
             </ul>
@@ -103,5 +106,5 @@
               <ul class="workout-info">
                 <li>
-                  <tal:c tal:content="workout.start_in_timezone(context.timezone)"></tal:c>
+                  <tal:c tal:content="workout.start_in_timezone(user.timezone)"></tal:c>
                 </li>
                 <li>
@@ -155,7 +158,7 @@
             <li>
               <span><tal:t i18n:translate="">Gender:</tal:t></span>
-              <tal:c tal:content="getattr(context, 'gender', '-')"></tal:c>
-            </li>
-            <li tal:define="birth_date getattr(context, 'birth_date', None)">
+              <tal:c tal:content="getattr(user, 'gender', '-')"></tal:c>
+            </li>
+            <li tal:define="birth_date getattr(user, 'birth_date', None)">
               <span><tal:t i18n:translate="">Birth date:</tal:t></span>
               <tal:c tal:condition="birth_date"
@@ -165,9 +168,9 @@
             <li>
               <span><tal:t i18n:translate="">Height:</tal:t></span>
-              <tal:c tal:content="getattr(context, 'height', '-')"></tal:c> meters
+              <tal:c tal:content="getattr(user, 'height', '-')"></tal:c> meters
             </li>
             <li>
               <span><tal:t i18n:translate="">Weight:</tal:t></span>
-              <tal:c tal:content="getattr(context, 'weight', '-')"></tal:c> kg
+              <tal:c tal:content="getattr(user, 'weight', '-')"></tal:c> kg
             </li>
           </ul>
@@ -195,6 +198,6 @@
          switcher_selector: '.js-month-stats .js-switcher a',
          is_active_class: 'is-active',
-         urls: {"monthly": "${request.resource_url(context, 'monthly')}",
-                "weekly": "${request.resource_url(context, 'weekly')}"},
+         urls: {"monthly": "${request.resource_url(user, 'monthly')}",
+                "weekly": "${request.resource_url(user, 'weekly')}"},
          current_month: "${current_month}",
          current_week: "${current_week}",
Index: ow/tests/models/test_root.py
===================================================================
--- ow/tests/models/test_root.py	(revision 4226ce04db48dcae8cd2a215b935d6ed69eca77e)
+++ ow/tests/models/test_root.py	(revision bddf042a37868bbfc94dcfcb533ec5ca46f2796e)
@@ -35,7 +35,7 @@
         # a new OpenWorkouts instance has a catalog created automatically
         assert isinstance(root.catalog, Catalog)
-        assert len(root.catalog) == 2
-        assert 'email' in root.catalog
-        assert 'sport' in root.catalog
+        assert len(root.catalog) == 3
+        for key in ['email', 'nickname', 'sport']:
+            assert key in root.catalog
 
     def test_add_user_ok(self, root):
Index: ow/tests/test_catalog.py
===================================================================
--- ow/tests/test_catalog.py	(revision 4226ce04db48dcae8cd2a215b935d6ed69eca77e)
+++ ow/tests/test_catalog.py	(revision bddf042a37868bbfc94dcfcb533ec5ca46f2796e)
@@ -56,5 +56,5 @@
         changes = update_indexes(catalog, indexes)
         assert changes['added'] == ['newindex']
-        assert changes['removed'] == ['email', 'sport']
+        assert changes['removed'] == ['email', 'nickname', 'sport']
 
     def test_update_indexes_empty(self, root):
@@ -63,5 +63,5 @@
         changes = update_indexes(catalog, indexes)
         assert changes['added'] == []
-        assert changes['removed'] == ['email', 'sport']
+        assert changes['removed'] == ['email', 'nickname', 'sport']
 
     def test_install_catalog(self):
Index: ow/tests/views/test_user.py
===================================================================
--- ow/tests/views/test_user.py	(revision 4226ce04db48dcae8cd2a215b935d6ed69eca77e)
+++ ow/tests/views/test_user.py	(revision bddf042a37868bbfc94dcfcb533ec5ca46f2796e)
@@ -270,6 +270,7 @@
         # profile page for the current day (no workouts avalable)
         response = user_views.profile(john, request)
-        assert len(response.keys()) == 4
+        assert len(response.keys()) == 5
         current_month = datetime.now(timezone.utc).strftime('%Y-%m')
+        assert response['user'] == john
         assert response['current_month'] == current_month
         assert response['current_week'] is None
@@ -284,5 +285,6 @@
         request.GET['month'] = 6
         response = user_views.profile(john, request)
-        assert len(response.keys()) == 4
+        assert len(response.keys()) == 5
+        assert response['user'] == john
         assert response['current_month'] == '2015-06'
         assert response['current_week'] is None
@@ -299,5 +301,6 @@
         request.GET['week'] = 25
         response = user_views.profile(john, request)
-        assert len(response.keys()) == 4
+        assert len(response.keys()) == 5
+        assert response['user'] == john
         assert response['current_month'] == '2015-06'
         assert response['current_week'] == 25
@@ -313,5 +316,6 @@
         request.GET['week'] = 26
         response = user_views.profile(john, request)
-        assert len(response.keys()) == 4
+        assert len(response.keys()) == 5
+        assert response['user'] == john
         assert response['current_month'] == '2015-06'
         assert response['current_week'] == 26
Index: ow/views/user.py
===================================================================
--- ow/views/user.py	(revision 4226ce04db48dcae8cd2a215b935d6ed69eca77e)
+++ ow/views/user.py	(revision bddf042a37868bbfc94dcfcb533ec5ca46f2796e)
@@ -4,5 +4,5 @@
 from decimal import Decimal
 
-from pyramid.httpexceptions import HTTPFound
+from pyramid.httpexceptions import HTTPFound, HTTPNotFound
 from pyramid.view import view_config
 from pyramid.security import remember, forget
@@ -157,4 +157,9 @@
 
 @view_config(
+    context=OpenWorkouts,
+    name='profile',
+    permission='view',
+    renderer='ow:templates/profile.pt')
+@view_config(
     context=User,
     permission='view',
@@ -166,9 +171,16 @@
     basic info, stats, etc
     """
+    if isinstance(context, OpenWorkouts):
+        nickname = request.subpath[0]
+        user = request.root.get_user_by_nickname(nickname)
+        if user is None:
+            return HTTPNotFound()
+    else:
+        user = context
     now = datetime.now(timezone.utc)
     year = int(request.GET.get('year', now.year))
     month = int(request.GET.get('month', now.month))
     week = request.GET.get('week', None)
-    workouts = context.workouts(year, month, week)
+    workouts = user.workouts(year, month, week)
     totals = {
         'distance': Decimal(0),
@@ -186,4 +198,5 @@
 
     return {
+        'user': user,
         'workouts': workouts,
         'current_month': '{year}-{month}'.format(
