diff --git a/bot/bot.go b/bot/bot.go
index 7712d579892d763afd91e135c9c09ac6f063cad1..f09e0263203186b1e8058ef02fae2918663a4a13 100644
--- a/bot/bot.go
+++ b/bot/bot.go
@@ -72,6 +72,7 @@ func (pb *PlayBot) ParseLine(author string, source string, line string, contents
 	var wg sync.WaitGroup
 
 	for _, url := range urls {
+		log.Print(url)
 		wg.Add(1)
 		go func(url string) {
 			defer wg.Done()
diff --git a/bot/collection.go b/bot/collection.go
index 5597c27e8ca16633cea827b589bc6597b58b1991..c1adf6c1e296031c61de118cdd33427f1ec53cc7 100644
--- a/bot/collection.go
+++ b/bot/collection.go
@@ -43,11 +43,11 @@ func (pbc *PlayBotCollection) InsertPost(post *Post) error {
 			return err
 		}
 
-        pbc.Db.Model(&content).Related(&content.Tags)
+		pbc.Db.Model(&content).Related(&content.Tags)
 
-        if len(post.Content.Tags) > 0 {
-            content.Tags = append(content.Tags, post.Content.Tags...)
-        }
+		if len(post.Content.Tags) > 0 {
+			content.Tags = append(content.Tags, post.Content.Tags...)
+		}
 		post.Content = &content
 	}
 
diff --git a/bot/db.go b/bot/db.go
index c4a76e42598a1170772c5ece195857655c4c138a..72cd2bd11ca31949766f67402a6b7581dfb846d1 100644
--- a/bot/db.go
+++ b/bot/db.go
@@ -20,8 +20,8 @@ type Db interface {
 	Error() error
 	Insert(interface{}) Db
 	First(interface{}) Db
-    Model(interface{}) Db
-    Related(interface{}) Db
+	Model(interface{}) Db
+	Related(interface{}) Db
 	Where(interface{}) Db
 }
 
diff --git a/main.go b/main.go
index 8f27e4fce144ef691dbfca0a23e6f32dbcbc66e9..f0c4652f80dd9bfa3f47a4bfa99398babd722323 100644
--- a/main.go
+++ b/main.go
@@ -9,7 +9,9 @@ import (
 
 	"git.iiens.net/morignot2011/playbot/bot"
 	"git.iiens.net/morignot2011/playbot/site"
+	"git.iiens.net/morignot2011/playbot/transport"
 	"git.iiens.net/morignot2011/playbot/transport/irc"
+	"git.iiens.net/morignot2011/playbot/transport/slack"
 )
 
 type config struct {
@@ -45,21 +47,25 @@ func startTransport(name string, config transportParams, factory bot.Factory) ch
 		log.Fatalf("Missing type for transport %s", name)
 	}
 
+	log.Printf("Start %s", name)
 	c := make(chan bool)
+	var t transport.Transport
+	var err error
 
 	switch transportType {
 	case "irc":
-		log.Printf("Start %s", name)
-		t, err := irc.New(name, config, factory, c)
-		if err != nil {
-			log.Fatalf("%s: %s", name, err)
-		}
-
-		if err := t.Run(); err != nil {
-			log.Fatalf("%s: %s", name, err)
-		}
+		t, err = irc.New(name, config, factory, c)
+	case "slack":
+		t, err = slack.New(name, config, factory, c)
 	}
 
+	if err != nil {
+		log.Fatalf("%s: %s", name, err)
+	}
+
+	if err := t.Run(); err != nil {
+		log.Fatalf("%s: %s", name, err)
+	}
 	return c
 }
 
diff --git a/site/tag.go b/site/tag.go
new file mode 100644
index 0000000000000000000000000000000000000000..37c0d5d8a77b081105b8f727411d0a9bb1130b64
--- /dev/null
+++ b/site/tag.go
@@ -0,0 +1,11 @@
+package site
+
+type Tag struct {
+	Tag       string `gorm:"primary_key:true"`
+	ContentId int    `gorm:"column:id;primary_key:true"`
+	Content   Content
+}
+
+func (Tag) TableName() string {
+	return "playbot_tags"
+}
diff --git a/transport/irc/events.go b/transport/irc/events.go
index 362f5d2b1fbd7610b417a5ad7a4cc1784eca854f..4a4a84eadae0d4e1e8f6c00e44b19db0905f8974 100644
--- a/transport/irc/events.go
+++ b/transport/irc/events.go
@@ -23,11 +23,11 @@ func (t *IrcTransport) disconnected(conn *irc.Conn, line *irc.Line) {
 func (t *IrcTransport) privmsg(conn *irc.Conn, line *irc.Line) {
 	channel := line.Target()
 	msg := line.Args[1]
-	b := t.bots[channel]
+	bot := t.bots[channel]
 	contents := make(chan *site.Content)
 
 	source := t.getSourceName(channel)
-	go b.ParseLine(line.Nick, source, msg, contents)
+	go bot.ParseLine(line.Nick, source, msg, contents)
 
 	for content := range contents {
 		t.printNewContent(conn, content, channel)
diff --git a/transport/irc/irc.go b/transport/irc/irc.go
index 5bede3ed091141909423778c1098380a47758239..bee292ddc9dbcae6270d220b4f81fa91d3652ae8 100644
--- a/transport/irc/irc.go
+++ b/transport/irc/irc.go
@@ -46,7 +46,6 @@ func New(name string, config map[string]interface{}, factory bot.Factory, quit c
 		return nil, transport.NewConfigurationError("chans")
 	}
 	for _, channel := range channels.([]interface{}) {
-		t.Logger.Print(channel)
 		t.channels = append(t.channels, channel.(string))
 	}
 
diff --git a/transport/slack/events.go b/transport/slack/events.go
new file mode 100644
index 0000000000000000000000000000000000000000..2f2213242670a46d8dd142d6904ed93678c74343
--- /dev/null
+++ b/transport/slack/events.go
@@ -0,0 +1,29 @@
+package slack
+
+import (
+	"github.com/nlopes/slack"
+
+	"git.iiens.net/morignot2011/playbot/site"
+)
+
+func (t *SlackTransport) connected(ev *slack.ConnectedEvent) {
+	t.Logger.Print("Connected")
+
+	for _, channel := range t.channels {
+		bot := t.botFactory.GetBot(t.Name)
+		t.bots[channel] = bot
+	}
+
+	t.bot = t.botFactory.GetBot(t.Name)
+}
+
+func (t *SlackTransport) message(ev *slack.MessageEvent) {
+	contents := make(chan *site.Content)
+
+	source := t.getSourceName(ev.Channel)
+	go t.bot.ParseLine(ev.User, source, ev.Text, contents)
+
+	for content := range contents {
+		t.printNewContent(content, ev.Channel)
+	}
+}
diff --git a/transport/slack/print.go b/transport/slack/print.go
new file mode 100644
index 0000000000000000000000000000000000000000..3d44dfbde38166088fb62eac50811cd0d41dc033
--- /dev/null
+++ b/transport/slack/print.go
@@ -0,0 +1,39 @@
+package slack
+
+import (
+	"fmt"
+
+	"git.iiens.net/morignot2011/playbot/site"
+)
+
+func (t *SlackTransport) printNewContent(content *site.Content, channel string) {
+	msg := fmt.Sprintf("[%d] %s", content.Id, content.Title)
+
+	if content.Author != "" {
+		msg += " | " + content.Author
+	}
+
+	if content.Duration > 0 {
+		h := content.Duration / 3600
+		m := (content.Duration % 3600) / 60
+		s := (content.Duration % 3600) % 60
+
+		msg += " ("
+
+		if h > 0 {
+			msg += fmt.Sprintf("%02d:", h)
+		}
+
+		if m > 0 {
+			msg += fmt.Sprintf("%02d:", m)
+		}
+
+		msg += fmt.Sprintf("%02d)", s)
+	}
+
+	for _, tag := range content.Tags {
+		msg += " #" + tag.Tag
+	}
+
+	t.rtm.SendMessage(t.rtm.NewOutgoingMessage(msg, channel))
+}
diff --git a/transport/slack/slack.go b/transport/slack/slack.go
new file mode 100644
index 0000000000000000000000000000000000000000..ddf2bf69f24cce126c8e3a6b19681dfed6798c04
--- /dev/null
+++ b/transport/slack/slack.go
@@ -0,0 +1,84 @@
+package slack
+
+import (
+	"fmt"
+	"log"
+	"os"
+
+	"github.com/nlopes/slack"
+
+	"git.iiens.net/morignot2011/playbot/bot"
+	"git.iiens.net/morignot2011/playbot/transport"
+)
+
+type SlackTransport struct {
+	transport.Base
+
+	api        *slack.Client
+	bot        bot.Bot
+	bots       map[string]bot.Bot
+	channels   []string
+	botFactory bot.Factory
+	rtm        *slack.RTM
+	quit       chan bool
+}
+
+func New(name string, config map[string]interface{}, factory bot.Factory, quit chan bool) (transport.Transport, error) {
+	token, ok := config["token"]
+	if !ok {
+		return nil, transport.NewConfigurationError("token")
+	}
+
+	api := slack.New(token.(string))
+	rtm := api.NewRTM()
+	t := &SlackTransport{
+		api:        api,
+		bots:       make(map[string]bot.Bot),
+		botFactory: factory,
+		rtm:        rtm,
+		quit:       quit,
+
+		Base: transport.Base{
+			Logger: log.New(os.Stdout, name, log.LstdFlags),
+			Name:   name,
+		},
+	}
+
+	channels, ok := config["chans"]
+	for _, channel := range channels.([]interface{}) {
+		t.channels = append(t.channels, channel.(string))
+	}
+
+	return t, nil
+}
+
+func (t *SlackTransport) Run() error {
+	go t.rtm.ManageConnection()
+	go t.dispatchEvents()
+
+	return nil
+}
+
+func (t *SlackTransport) dispatchEvents() {
+	for {
+		select {
+		case msg := <-t.rtm.IncomingEvents:
+			switch ev := msg.Data.(type) {
+			case *slack.ConnectedEvent:
+				t.connected(ev)
+			case *slack.MessageEvent:
+				t.message(ev)
+			case *slack.InvalidAuthEvent:
+				t.Logger.Printf("Invalid credentials")
+				t.quit <- true
+				return
+			case *slack.RTMError:
+				t.Logger.Printf("Error: %q", ev)
+			}
+		}
+	}
+}
+
+func (t *SlackTransport) getSourceName(channel string) string {
+	return fmt.Sprintf("%s@%s", channel, t.Name)
+}