diff --git a/doc/README.md b/doc/README.md
index f87a864..d7deebf 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -18,8 +18,9 @@ automatically logged in and validated against mojang's auth.
  * maxPlayers : default to 20
  * keepAlive : send keep alive packets : default to true
  * version : 1.8 or 1.9 : default to 1.8
+ * customPackets (optional) : an object index by state/direction/name, see client_custom_packet for an example
 
-## mc.Server(version)
+## mc.Server(version,[customPackets])
 
 Create a server instance for `version` of minecraft.
 
@@ -74,8 +75,9 @@ Returns a `Client` instance and perform login.
  * keepAlive : send keep alive packets : default to true
  * checkTimeoutInterval : default to `10*1000` (10s), check if keepalive received at that period, disconnect otherwise.
  * version : 1.8 or 1.9 or false (to auto-negotiate): default to 1.8
+ * customPackets (optional) : an object index by state/direction/name, see client_custom_packet for an example
 
-## mc.Client(isServer,version)
+## mc.Client(isServer,version,[customPackets])
 
 Create a new client, if `isServer` is true then it is a server-side client, otherwise it's a client-side client.
 Takes a minecraft `version` as second argument.
diff --git a/examples/client_custom_packets/client_custom_packets.js b/examples/client_custom_packets/client_custom_packets.js
new file mode 100644
index 0000000..a7fa7c1
--- /dev/null
+++ b/examples/client_custom_packets/client_custom_packets.js
@@ -0,0 +1,54 @@
+var mc = require('minecraft-protocol');
+
+if(process.argv.length < 4 || process.argv.length > 6) {
+  console.log("Usage : node echo.js <host> <port> [<name>] [<password>]");
+  process.exit(1);
+}
+
+var customPackets={
+  "play":{
+    "toClient":{
+      "my_custom_packet": {
+        "id": "0x7A",
+        "fields": [
+          {
+            "name": "age",
+            "type": "i64"
+          },
+          {
+            "name": "time",
+            "type": "i64"
+          }
+        ]
+      }
+    }
+  }
+};
+
+var client = mc.createClient({
+  host: process.argv[2],
+  port: parseInt(process.argv[3]),
+  username: process.argv[4] ? process.argv[4] : "echo",
+  password: process.argv[5],
+  customPackets:customPackets
+});
+
+client.on('connect', function() {
+  console.info('connected');
+});
+client.on('disconnect', function(packet) {
+  console.log('disconnected: '+ packet.reason);
+});
+client.on('end', function(err) {
+  console.log('Connection lost');
+});
+
+client.on('login',function(){
+  client.deserializer.write(new Buffer("7A0000000000909327fffffffffffffc18","hex"));
+  console.log('login');
+
+});
+
+client.on('my_custom_packet',function(packet){
+  console.log(packet);
+});
diff --git a/examples/client_custom_packets/package.json b/examples/client_custom_packets/package.json
new file mode 100644
index 0000000..56fcdf2
--- /dev/null
+++ b/examples/client_custom_packets/package.json
@@ -0,0 +1,8 @@
+{
+  "name": "node-minecraft-protocol-example",
+  "version": "0.0.0",
+  "private": true,
+  "dependencies": {
+  },
+  "description": "A node-minecraft-protocol example"
+}
diff --git a/src/client.js b/src/client.js
index 51b22d2..eb6e614 100644
--- a/src/client.js
+++ b/src/client.js
@@ -10,8 +10,9 @@ const createDeserializer=require("./transforms/serializer").createDeserializer;
 
 class Client extends EventEmitter
 {
-  constructor(isServer,version) {
+  constructor(isServer,version,customPackets) {
     super();
+    this.customPackets=customPackets;
     this.version=version;
     this.isServer = !!isServer;
     this.splitter=framing.createSplitter();
@@ -46,9 +47,9 @@ class Client extends EventEmitter
 
 
   setSerializer(state) {
-    this.serializer = createSerializer({ isServer:this.isServer, version:this.version, state: state});
+    this.serializer = createSerializer({ isServer:this.isServer, version:this.version, state: state,customPackets:this.customPackets});
     this.deserializer = createDeserializer({ isServer:this.isServer, version:this.version, state: state, packetsToParse:
-      this.packetsToParse});
+      this.packetsToParse,customPackets:this.customPackets});
 
     this.splitter.recognizeLegacyPing = state === states.HANDSHAKING;
 
diff --git a/src/createClient.js b/src/createClient.js
index 11d3a31..ee5ab96 100644
--- a/src/createClient.js
+++ b/src/createClient.js
@@ -25,7 +25,7 @@ function createClient(options) {
   options.majorVersion = version.majorVersion;
   options.protocolVersion = version.version;
 
-  const client = new Client(false, version.minecraftVersion);
+  const client = new Client(false, version.minecraftVersion,options.customPackets);
 
   tcp_dns(client, options);
   caseCorrect(client, options);
diff --git a/src/createServer.js b/src/createServer.js
index af705e8..fe25f60 100644
--- a/src/createServer.js
+++ b/src/createServer.js
@@ -32,7 +32,7 @@ function createServer(options) {
 
   const serverKey = ursa.generatePrivateKey(1024);
 
-  const server = new Server(version.minecraftVersion);
+  const server = new Server(version.minecraftVersion,options.customPackets);
   server.motd = options.motd || "A Minecraft server";
   server.maxPlayers = options['max-players'] || 20;
   server.playerCount = 0;
diff --git a/src/server.js b/src/server.js
index daab15e..fb96fa2 100644
--- a/src/server.js
+++ b/src/server.js
@@ -5,13 +5,14 @@ const states = require("./states");
 
 class Server extends EventEmitter
 {
-  constructor(version) {
+  constructor(version,customPackets) {
     super();
     this.version=version;
     this.socketServer=null;
     this.cipher=null;
     this.decipher=null;
     this.clients={};
+    this.customPackets=customPackets;
   }
 
   listen(port, host) {
@@ -19,7 +20,7 @@ class Server extends EventEmitter
     let nextId = 0;
     self.socketServer = net.createServer();
     self.socketServer.on('connection', socket => {
-      const client = new Client(true,this.version);
+      const client = new Client(true,this.version,this.customPackets);
       client._end = client.end;
       client.end = function end(endReason) {
         endReason='{"text":"'+endReason+'"}';
diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js
index 23cc982..9eb1f1c 100644
--- a/src/transforms/serializer.js
+++ b/src/transforms/serializer.js
@@ -36,21 +36,23 @@ function createProtocol(types,packets)
   return proto;
 }
 
-function createSerializer({ state = states.HANDSHAKING, isServer = false , version} = {})
+function createSerializer({ state = states.HANDSHAKING, isServer = false , version,customPackets} = {})
 {
   const mcData=require("minecraft-data")(version);
   const direction = !isServer ? 'toServer' : 'toClient';
   const packets = mcData.protocol.states[state][direction];
+  if(customPackets &&  customPackets[state] && customPackets[state][direction]) Object.keys(customPackets[state][direction]).forEach(name => packets[name]=customPackets[state][direction][name]);
   const proto=createProtocol(mcData.protocol.types,packets);
   return new Serializer(proto,"packet");
 }
 
 function createDeserializer({ state = states.HANDSHAKING, isServer = false,
-  packetsToParse = {"packet": true}, version } = {})
+  packetsToParse = {"packet": true}, version,customPackets } = {})
 {
   const mcData=require("minecraft-data")(version);
   const direction = isServer ? "toServer" : "toClient";
   const packets = mcData.protocol.states[state][direction];
+  if(customPackets &&  customPackets[state] && customPackets[state][direction]) Object.keys(customPackets[state][direction]).forEach(name => packets[name]=customPackets[state][direction][name]);
   const proto=createProtocol(mcData.protocol.types,packets);
   return new Parser(proto,"packet");
 }