diff --git a/controllers/data_controller/export_controller.go b/controllers/data_controller/export_controller.go
index 67dfd063a552291d5bbc5d4281e57fc3070938ac..45fe10fc02b89387280ee3c470a900c52eb6f3b1 100644
--- a/controllers/data_controller/export_controller.go
+++ b/controllers/data_controller/export_controller.go
@@ -16,6 +16,7 @@ import (
 	"github.com/turt2live/matrix-media-repo/common/config"
 	"github.com/turt2live/matrix-media-repo/storage"
 	"github.com/turt2live/matrix-media-repo/storage/datastore"
+	"github.com/turt2live/matrix-media-repo/storage/datastore/ds_s3"
 	"github.com/turt2live/matrix-media-repo/templating"
 	"github.com/turt2live/matrix-media-repo/types"
 	"github.com/turt2live/matrix-media-repo/util"
@@ -183,12 +184,16 @@ func StartUserExport(userId string, s3urls bool, includeData bool, log *logrus.E
 		}
 		mediaManifest := make(map[string]*manifestRecord)
 		for _, m := range media {
+			s3url, err := ds_s3.GetS3URL(m.DatastoreId, m.Location)
+			if err != nil {
+				log.Warn(err)
+			}
 			mediaManifest[m.MxcUri()] = &manifestRecord{
 				ArchivedName: archivedName(m),
 				FileName:     m.UploadName,
 				SizeBytes:    m.SizeBytes,
 				ContentType:  m.ContentType,
-				S3Url:        "TODO",
+				S3Url:        s3url,
 				Sha256:       m.Sha256Hash,
 				Origin:       m.Origin,
 				MediaId:      m.MediaId,
diff --git a/storage/datastore/ds_s3/s3_store.go b/storage/datastore/ds_s3/s3_store.go
index 7c53ba1868df07e8fc136b40a1c5b5e4f88d1e81..64c7ba3f87f69f39d717374c3b21ab28c8dc1074 100644
--- a/storage/datastore/ds_s3/s3_store.go
+++ b/storage/datastore/ds_s3/s3_store.go
@@ -2,6 +2,7 @@ package ds_s3
 
 import (
 	"context"
+	"fmt"
 	"io"
 	"io/ioutil"
 	"os"
@@ -64,6 +65,17 @@ func GetOrCreateS3Datastore(dsId string, conf config.DatastoreConfig) (*s3Datast
 	return s3ds, nil
 }
 
+func GetS3URL(datastoreId string, location string) (string, error) {
+	var store *s3Datastore
+	var ok bool
+	if store, ok = stores[datastoreId]; !ok {
+		return "", errors.New("s3 datastore not found")
+	}
+
+	// HACK: Surely there's a better way...
+	return fmt.Sprintf("https://%s/%s/%s", store.conf.Options["endpoint"], store.bucket, location), nil
+}
+
 func (s *s3Datastore) EnsureBucketExists() error {
 	found, err := s.client.BucketExists(s.bucket)
 	if err != nil {